android实现弹幕 三行展示,数据不重复,不重叠,还能发弹幕:
Android开源弹幕引擎·烈焰弹幕使 ~:https://github.com/bilibili/DanmakuFlameMaster (大家都在用这玩意,但是确实不太友好,改起来有点方;不过算是不错的了,至少有开源的源码)
1、添加依赖:
dependencies {
implementation 'com.github.ctiao:DanmakuFlameMaster:0.9.16'
}
2、简单实现:
实现逻辑:
1》、初始化弹幕的列表数据集,启动线程循环展示
2》、添加一条弹幕,并且存入列表数据集,保证数据不丢失
代码逻辑很简单,先看代码,合适再用,不合适仅供参考
import master.flame.danmaku.controller.DanmakuFilters;
import master.flame.danmaku.controller.DrawHandler;
import master.flame.danmaku.danmaku.model.BaseDanmaku;
import master.flame.danmaku.danmaku.model.DanmakuTimer;
import master.flame.danmaku.danmaku.model.IDanmakus;
import master.flame.danmaku.danmaku.model.IDisplayer;
import master.flame.danmaku.danmaku.model.android.DanmakuContext;
import master.flame.danmaku.danmaku.model.android.Danmakus;
import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;
import master.flame.danmaku.ui.widget.DanmakuView;
public class MainActivity extends Activity {
private boolean showDanmaku;//是否循环展示弹幕
private DanmakuView danmakuView;//弹幕View
private DanmakuContext danmakuContext;//弹幕的Context使用对象
List<DanMuBean> totalDanMuList = new ArrayList<>();//用于记录弹幕的内容列表
private BaseDanmakuParser parser = new BaseDanmakuParser() {
@Override
protected IDanmakus parse() {
return new Danmakus();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
VideoView videoView = (VideoView) findViewById(R.id.video_view);
videoView.setVideoPath("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4");
videoView.start();
Button button = (Button)findViewById(R.id.addDanmu);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DanMuBean danMuBean = new DanMuBean();
danMuBean.setContent("漠天");
danMuBean.setShowBorder(true);
totalDanMuList.add(danMuBean);
addDanmaku(danMuBean.getContent(), danMuBean.isShowBorder());
}
});
danmakuView = (DanmakuView) findViewById(R.id.danmaku_view);
danmakuView.enableDanmakuDrawingCache(true);
danmakuView.setCallback(new DrawHandler.Callback() {
@Override
public void prepared() {
showDanmaku = true;
danmakuView.start();
//初始化弹幕列表,可以替换成自己的数据集
for(int index=0;index<20;index++) {
DanMuBean danMuBean = new DanMuBean();
danMuBean.setContent("丫头 ("+index+")");
danMuBean.setShowBorder(false);
totalDanMuList.add(danMuBean);
}
//启动线程展示弹幕
generateSomeDanmaku();
}
@Override
public void updateTimer(DanmakuTimer timer) {
}
@Override
public void danmakuShown(BaseDanmaku danmaku) {
}
@Override
public void drawingFinished() {
}
});
danmakuContext = DanmakuContext.create();
danmakuView.prepare(parser, danmakuContext);
// 设置最大显示行数
HashMap<Integer, Integer> maxLinesPair = new HashMap<Integer, Integer>();
maxLinesPair.put(BaseDanmaku.TYPE_SCROLL_RL, 3); // 滚动弹幕最大显示5行
// 设置是否禁止重叠
HashMap<Integer, Boolean> overlappingEnablePair = new HashMap<Integer, Boolean>();
overlappingEnablePair.put(BaseDanmaku.TYPE_SCROLL_RL, true);
overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_TOP, true);
danmakuContext.setDanmakuStyle(IDisplayer.DANMAKU_STYLE_STROKEN, 3)
.setDuplicateMergingEnabled(false)
.setScrollSpeedFactor(1.2f)
.setScaleTextSize(1.2f)
.setDuplicateMergingEnabled(false) //设置不合并相同内容弹幕
.preventOverlapping(overlappingEnablePair)
.setMaximumLines(maxLinesPair);
}
/**
* 向弹幕View中添加一条弹幕
* @param content
* 弹幕的具体内容
* @param withBorder
* 弹幕是否有边框
*/
private void addDanmaku(String content, boolean withBorder) {
BaseDanmaku danmaku = danmakuContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
danmaku.text = content;
danmaku.padding = 5;
danmaku.textSize = sp2px(20);
danmaku.textColor = Color.WHITE;
danmaku.setTime(danmakuView.getCurrentTime());
if (withBorder) {
danmaku.borderColor = Color.GREEN;
}
danmakuView.addDanmaku(danmaku);
}
/**
* 循环展示弹幕,展示列表的弹幕
*/
private void generateSomeDanmaku() {
new Thread(new Runnable() {
@Override
public void run() {
while(showDanmaku) {
for(int index = 0;index<totalDanMuList.size();index++){
int time = new Random().nextInt(1000);
DanMuBean danMuBean = totalDanMuList.get(index);
if(danMuBean!=null) {
addDanmaku(danMuBean.getContent(), danMuBean.isShowBorder());
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}).start();
}
/**
* sp转px的方法。
*/
public int sp2px(float spValue) {
final float fontScale = getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
@Override
protected void onPause() {
super.onPause();
if (danmakuView != null && danmakuView.isPrepared()) {
danmakuView.pause();
}
}
@Override
protected void onResume() {
super.onResume();
if (danmakuView != null && danmakuView.isPrepared() && danmakuView.isPaused()) {
danmakuView.resume();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
showDanmaku = false;
if (danmakuView != null) {
danmakuView.release();
danmakuView = null;
}
}
}
3、xml代码:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimaryDark"
tools:context=".MainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:gravity="center">
<VideoView
android:id="@+id/video_view"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_centerInParent="true" />
<master.flame.danmaku.ui.widget.DanmakuView
android:id="@+id/danmaku_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
<Button
android:id="@+id/addDanmu"
android:layout_width="200dp"
android:layout_height="100dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="50dp"
android:text="添加弹幕"
android:textColor="#ff0000"
android:textSize="20sp" />
</RelativeLayout>