首先import 弹幕包
import master.flame.danmaku.danmaku.util.SystemClock;
import master.flame.danmaku.controller.IDanmakuView;
import master.flame.danmaku.danmaku.loader.ILoader;
import master.flame.danmaku.danmaku.loader.IllegalDataException;
import master.flame.danmaku.danmaku.loader.android.DanmakuLoaderFactory;
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.BaseCacheStuffer;
import master.flame.danmaku.danmaku.model.android.DanmakuContext;
import master.flame.danmaku.danmaku.model.android.Danmakus;
import master.flame.danmaku.danmaku.model.android.SpannedCacheStuffer;
import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;
import master.flame.danmaku.danmaku.parser.IDataSource;
import master.flame.danmaku.danmaku.parser.android.BiliDanmukuParser;
import master.flame.danmaku.danmaku.util.IOUtils;
定义全局变量
private IDanmakuView mDanmakuView;
private BaseDanmakuParser mParser;
private DanmakuContext mContext;
启动单个线程加载远程图片
private BaseCacheStuffer.Proxy mCacheStufferAdapter = new BaseCacheStuffer.Proxy() {
private Drawable mDrawable;
@Override
public void prepareDrawing(final BaseDanmaku danmaku, boolean fromWorkerThread) {
if (danmaku.text instanceof Spanned) { // 根据你的条件检查是否需要需要更新弹幕
// FIXME 这里只是简单启个线程来加载远程url图片,请使用你自己的异步线程池,最好加上你的缓存池
new Thread() {
@Override
public void run() {
String url = "http://vod.vbyte.cn/leifeng32.ico";
InputStream inputStream = null;
Drawable drawable = mDrawable;
if(drawable == null) {
try {
URLConnection urlConnection = new URL(url).openConnection();
inputStream = urlConnection.getInputStream();
drawable = BitmapDrawable.createFromStream(inputStream, "bitmap");
mDrawable = drawable;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(inputStream);
}
}
if (drawable != null) {
drawable.setBounds(0, 0, 100, 100);
SpannableStringBuilder spannable = createSpannable(drawable);
danmaku.text = spannable;
if(mDanmakuView != null) {
mDanmakuView.invalidateDanmaku(danmaku, false);
}
return;
}
}
}.start();
}
}
@Override
public void releaseResource(BaseDanmaku danmaku) {
// TODO 重要:清理含有ImageSpan的text中的一些占用内存的资源 例如drawable
}
};
设置最大显示行数及是否进制重叠
HashMap<Integer, Integer> maxLinesPair = new HashMap<Integer, Integer>();
// 滚动弹幕最大显示5行
maxLinesPair.put(BaseDanmaku.TYPE_SCROLL_RL, 5);
HashMap<Integer, Boolean> overlappingEnablePair = new HashMap<Integer, Boolean>();
overlappingEnablePair.put(BaseDanmaku.TYPE_SCROLL_RL, true);
overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_TOP, true);
接下来初始化上面定义的最关键三个全局变量
mDanmakuView = (IDanmakuView) findViewById(R.id.sv_danmaku);
mContext = DanmakuContext.create();
mContext.setDanmakuStyle(IDisplayer.DANMAKU_STYLE_STROKEN,3)
.setDuplicateMergingEnabled(false)
.setScaleTextSize(1.2f)
// 图文混排使用SpannedCacheStuffer
.setCacheStuffer(new SpannedCacheStuffer(), mCacheStufferAdapter)
.setMaximumLines(maxLinesPair)
.preventOverlapping(overlappingEnablePair);
if (mDanmakuView != null) {
//很明显,这就是我们弹幕的显示资源
mParser = createParser(this.getResources().openRawResource(R.raw.comments));
mDanmakuView.setCallback(new master.flame.danmaku.controller.DrawHandler.Callback() {
@Override
public void updateTimer(DanmakuTimer timer) {
}
@Override
public void drawingFinished() {
}
@Override
public void danmakuShown(BaseDanmaku danmaku) {
}
@Override
public void prepared() {
mDanmakuView.start();
}
});
mDanmakuView.setOnDanmakuClickListener(new IDanmakuView.OnDanmakuClickListener() {
@Override
public void onDanmakuClick(BaseDanmaku latest) {
}
@Override
public void onDanmakuClick(IDanmakus danmakus) {
}
});
mDanmakuView.prepare(mParser, mContext);
mDanmakuView.showFPS(true);
mDanmakuView.enableDanmakuDrawingCache(true);
((View) mDanmakuView).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mMediaController.setVisibility(View.VISIBLE);
}
});
}
下面是跟随播放器的一些弹幕库的暂定、播放、释放资源的操作
@Override
protected void onPause() {
super.onPause();
if (mDanmakuView != null && mDanmakuView.isPrepared()) {
mDanmakuView.pause();
}
}
@Override
protected void onResume() {
super.onResume();
if (mDanmakuView != null && mDanmakuView.isPrepared() && mDanmakuView.isPaused()) {
mDanmakuView.resume();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mDanmakuView != null) {
// dont forget release!
mDanmakuView.release();
mDanmakuView = null;
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
if (mDanmakuView != null) {
// dont forget release!
mDanmakuView.release();
mDanmakuView = null;
}
}
弹幕的一些属性操作,可用户自设置,易理解,不解释
mDanmakuView.hide();
mDanmakuView.show();
mDanmakuView.pause();
mDanmakuView.resume();
来一条纯文本弹幕测试一下
private void addDanmaku(boolean islive) {
BaseDanmaku danmaku = mContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
if (danmaku == null || mDanmakuView == null) {
return;
}
danmaku.text = "这就是一条测试,至于你信不信,反正我是信了";
danmaku.padding = 5;
// 优先级,>0为高优先级不会被过滤器过滤,会被各种过滤器过滤并隐藏显示
danmaku.priority = 0;
danmaku.isLive = islive;
danmaku.time = mDanmakuView.getCurrentTime() + 1200;
danmaku.textSize = 25f * (mParser.getDisplayer().getDensity() - 0.6f);
danmaku.textColor = Color.RED;
danmaku.textShadowColor = Color.WHITE;
danmaku.underlineColor = Color.GREEN;
danmaku.borderColor = Color.GREEN;
mDanmakuView.addDanmaku(danmaku);
}
来一条图文混编的测试一下,SpannableStringBuilder
private void addDanmaKuShowTextAndImage(boolean islive) {
BaseDanmaku danmaku = mContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
Drawable drawable = getResources().getDrawable(R.drawable.ic_launcher);
drawable.setBounds(0, 0, 100, 100);
String text = "bitmap";
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(text);
ImageSpan span = new ImageSpan(drawable);//ImageSpan.ALIGN_BOTTOM);
spannableStringBuilder.setSpan(span, 0, text.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
spannableStringBuilder.append("我只是个图文混排的测试");
spannableStringBuilder.setSpan(new BackgroundColorSpan(Color.parseColor("#8A2233B1")), 0, spannableStringBuilder.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
//以上部分是与纯文本的区别,显示资源的区别
danmaku.text = spannable;
danmaku.padding = 5;
danmaku.priority = 1; // 一定会显示, 一般用于本机发送的弹幕
danmaku.isLive = islive;
danmaku.time = mDanmakuView.getCurrentTime() + 1200;
danmaku.textSize = 25f * (mParser.getDisplayer().getDensity() - 0.6f);
danmaku.textColor = Color.RED;
danmaku.textShadowColor = 0; // 重要:如果有图文混排,最好不要设置描边(设textShadowColor=0),否则会进行两次复杂的绘制导致运行效率降低
danmaku.underlineColor = Color.GREEN;
mDanmakuView.addDanmaku(danmaku);
}
本文详细介绍了弹幕系统的开发流程,包括导入依赖、初始化关键全局变量、加载远程图片、弹幕显示设置、属性操作以及播放器交互。通过实例演示如何实现弹幕的创建、展示和管理。
1万+

被折叠的 条评论
为什么被折叠?



