Introduction
OpenDanmaku is a third-party barrage control in Android, which pops up user comments during video playback and live broadcast software, and displays them in a scrolling manner.
use
- Download link: https://github.com/linsea/OpenDanmaku
- Project related library
Gradle
dependencies {
compile 'com.linsea:opendanmaku:1.0.0@aar'
}
//或者引用本地lib
compile project(':opendanmaku')
Case study
- MainActivity
package com.example.dell.myapplication;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.ImageSpan;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.MediaController;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.VideoView;
import com.opendanmaku.DanmakuItem;
import com.opendanmaku.DanmakuView;
import com.opendanmaku.IDanmakuItem;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class OpenDanmakuMainActivity extends AppCompatActivity implements View.OnClickListener{
/**
* 定义控件
*/
private DanmakuView mDanmakuView;
private Button switcherBtn;
private Button sendBtn;
private EditText textEditText;
private VideoView videoView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_open_danmaku_main);
//实例化控件
mDanmakuView = (DanmakuView) findViewById(R.id.danmakuView);
switcherBtn = (Button) findViewById(R.id.switcher);
sendBtn = (Button) findViewById(R.id.send);
textEditText = (EditText) findViewById(R.id.text);
videoView = (VideoView) findViewById(R.id.videoView);
//设置相关播放视频
setVideoView();
//重点
List<IDanmakuItem> list = initItems();
//变成随机数据
Collections.shuffle(list);
//添加到弹幕控件里面
mDanmakuView.addItem(list, true);
switcherBtn.setOnClickListener(this);
sendBtn.setOnClickListener(this);
}
/**
* 播放视频想
*/
private void setVideoView() {
//设置准备好的监听
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
videoView.start();//开始播放
}
});
//设置播放完成
videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
videoView.start();//重新开始播放
}
});
//设置播放出错
videoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Toast.makeText(OpenDanmakuMainActivity.this, "播放出错了", Toast.LENGTH_SHORT).show();
return true;
}
});
//设置控制面板
videoView.setMediaController(new MediaController(this));
//设置播放地址
videoView.setVideoPath("http://vfx.mtime.cn/Video/2016/12/12/mp4/161212190638286683_480.mp4");
// videoView.setVideoPath("http://192.168.11.218:8080/oppo.mp4");
}
/**
* 构建弹幕的数据集合
* @return
*/
private List<IDanmakuItem> initItems() {
List<IDanmakuItem> list = new ArrayList<>();
//创建100条文本的弹幕
for (int i = 0; i < 100; i++) {
IDanmakuItem item = new DanmakuItem(this, i + " : plain text danmuku", mDanmakuView.getWidth());
list.add(item);
}
//创建100条文本带图片的弹幕
String msg = " : text with image ";
for (int i = 0; i < 100; i++) {
ImageSpan imageSpan = new ImageSpan(this, R.drawable.em);
SpannableString spannableString = new SpannableString(i + msg);
spannableString.setSpan(imageSpan, spannableString.length() - 2, spannableString.length() - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
IDanmakuItem item = new DanmakuItem(this, spannableString, mDanmakuView.getWidth(), 0, 0, 0, 1.5f);
list.add(item);
}
return list;
}
@Override
protected void onResume() {
super.onResume();
//显示弹幕
mDanmakuView.show();
}
@Override
protected void onPause() {
super.onPause();
//隐藏弹幕弹幕
mDanmakuView.hide();
}
@Override
protected void onDestroy() {
super.onDestroy();
//清除弹幕
mDanmakuView.clear();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.switcher:
if (mDanmakuView.isPaused()) {
switcherBtn.setText(R.string.hide);
mDanmakuView.show();
} else {
switcherBtn.setText(R.string.show);
mDanmakuView.hide();
}
break;
case R.id.send:
String input = textEditText.getText().toString();
if (TextUtils.isEmpty(input)) {
Toast.makeText(OpenDanmakuMainActivity.this, R.string.empty_prompt, Toast.LENGTH_SHORT).show();
} else {
IDanmakuItem item = new DanmakuItem(this, new SpannableString(input), mDanmakuView.getWidth(),0,R.color.my_item_color,0,1);
// IDanmakuItem item = new DanmakuItem(this, input, mDanmakuView.getWidth());
// item.setTextColor(getResources().getColor(R.color.my_item_color));
// item.setTextSize(14);
// item.setTextColor(textColor);
mDanmakuView.addItemToHead(item);
}
textEditText.setText("");
break;
}
}
}
- layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/default_bg"
android:orientation="vertical"
tools:context=".MainActivity">
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="200dp"
android:background="@color/default_bg">
<!-- put a VideoView/SurfaceView here if you want show Danmaku on top of video-->
<VideoView
android:id="@+id/videoView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/bg_color" />
<com.opendanmaku.DanmakuView
android:id="@+id/danmakuView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
app:end_Y_offset="0.8"
app:max_row="4"
app:max_running_per_row="2"
app:pick_interval="1000"
app:show_debug="false"
app:start_Y_offset="0.2" />
</FrameLayout>
<Button
android:id="@+id/switcher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="10dp"
android:text="hide" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp">
<EditText
android:id="@+id/text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="1"
android:hint="input text here" />
<Button
android:id="@+id/send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="send" />
</LinearLayout>
</LinearLayout>
- Note: You can add a barrage to the screen through the above steps, but the barrage is like a view that will cover the content of the videoview, so you need to change the source code of OpenDanmaku.
- As follows: Find the onDraw method in the DanmakuView.java file and make the following changes
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (status == STATUS_RUNNING) {
try {
// canvas.drawColor(Color.TRANSPARENT);//将这句代码注释掉添加下面一句代码即可
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
//先绘制正在播放的弹幕
for (int i = 0; i < mChannelMap.size(); i++) {
ArrayList<IDanmakuItem> list = mChannelMap.get(i);
for (Iterator<IDanmakuItem> it = list.iterator(); it.hasNext(); ) {
IDanmakuItem item = it.next();
if (item.isOut()) {
it.remove();
} else {
item.doDraw(canvas);
}
}
}
//检查是否需要加载播放下一个弹幕
if (System.currentTimeMillis() - previousTime > mPickItemInterval) {
previousTime = System.currentTimeMillis();
// Log.d(TAG, "start pick new item..");
IDanmakuItem di = mWaitingItems.pollFirst();
if (di != null) {
int indexY = findVacant(di);
if (indexY >= 0) {
// Log.d(TAG, "find vacant channel");
di.setStartPosition(canvas.getWidth() - 2, mChannelY[indexY]);
// Log.d(TAG, "draw new, text:" + di.getText());
//Log.d(TAG, String.format("doDraw, position,x=%s,y=%s", c.getWidth() - 1, mChannelY[indexY]));
di.doDraw(canvas);
mChannelMap.get(indexY).add(di);//不要忘记加入正运行的维护的列表中
} else {
// Log.d(TAG, "Not find vacant channel, add it back");
addItemToHead(di);//找不到可以播放的弹道,则把它放回列表中
}
} else {
//no item 弹幕播放完毕,
}
}
if (mShowDebug) {
int fps = (int) fps();
canvas.drawText("FPS:" + fps, 5f, 20f, fpsPaint);
for (float yp : lines) {
canvas.drawLine(0f, yp, getWidth(), yp, fpsPaint);
}
}
} catch (Exception e) {
e.printStackTrace();
}
invalidate();
} else {
//暂停或停止,隐藏弹幕内容
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
}
}