开源弹幕引擎·烈焰弹幕使(DanmakuFlameMaster)使用解析

来源:互联网 发布:fastqc数据质控报告 编辑:程序博客网 时间:2024/04/20 08:07

简介

DanmakuFlameMaster 是 Android 上开源弹幕解析绘制引擎项目,也是 Android 上最好的开源弹幕引擎·烈焰弹幕。其架构清晰,简单易用,支持多种高效率绘制方式选择,支持多种自定义功能设置上。目前,DanmakuFlameMaster 开发包已被包括优酷土豆、开迅视频、MissEvan、echo回声、斗鱼TV、天天动听、被窝声次元、ACFUN 等 APP 使用。Features使用多种方式(View/SurfaceView/TextureView)实现高效绘制B站xml弹幕格式解析基础弹幕精确还原绘制支持mode7特殊弹幕多核机型优化,高效的预缓存机制支持多种显示效果选项实时切换实时弹幕显示支持换行弹幕支持/运动弹幕支持支持自定义字体支持多种弹幕参数设置支持多种方式的弹幕屏蔽TODO:继续精确/稳定绘帧周期增加OpenGL ES绘制方式改进缓存策略和效率

github地址:https://github.com/Bilibili/DanmakuFlameMaster

demo示例
这里写图片描述

集成方法

build.gradle中添加

dependencies {    compile 'com.github.ctiao:dfm:0.4.2'}

使用方法

一、布局文件定义

<master.flame.danmaku.ui.widget.DanmakuView    android:id="@+id/sv_danmaku"    android:layout_width="match_parent"    android:layout_height="match_parent" />

二、初始化

private BaseDanmakuParser mParser;//解析器对象private IDanmakuView mDanmakuView;//实例化mDanmakuView = (IDanmakuView) findViewById(R.id.sv_danmaku);private DanmakuContext mContext;mContext = DanmakuContext.create();// 设置弹幕的最大显示行数HashMap<Integer, Integer> maxLinesPair = new HashMap<Integer, Integer>();maxLinesPair.put(BaseDanmaku.TYPE_SCROLL_RL, 3); // 滚动弹幕最大显示3行// 设置是否禁止重叠HashMap<Integer, Boolean> overlappingEnablePair = new HashMap<Integer, Boolean>();overlappingEnablePair.put(BaseDanmaku.TYPE_SCROLL_LR, true);overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_BOTTOM, true);mContext.setDanmakuStyle(IDisplayer.DANMAKU_STYLE_STROKEN, 3) //设置描边样式            .setDuplicateMergingEnabled(false)            .setScrollSpeedFactor(1.2f) //是否启用合并重复弹幕            .setScaleTextSize(1.2f) //设置弹幕滚动速度系数,只对滚动弹幕有效            .setCacheStuffer(new SpannedCacheStuffer(), mCacheStufferAdapter) // 图文混排使用SpannedCacheStuffer  设置缓存绘制填充器,默认使用{@link SimpleTextCacheStuffer}只支持纯文字显示, 如果需要图文混排请设置{@link SpannedCacheStuffer}如果需要定制其他样式请扩展{@link SimpleTextCacheStuffer}|{@link SpannedCacheStuffer}            .setMaximumLines(maxLinesPair) //设置最大显示行数            .preventOverlapping(overlappingEnablePair); //设置防弹幕重叠,null为允许重叠if (mDanmakuView != null) {        mParser = createParser(this.getResources().openRawResource(R.raw.comments)); //创建解析器对象,从raw资源目录下解析comments.xml文本        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.prepare(mParser, mContext);    mDanmakuView.showFPS(false); //是否显示FPS    mDanmakuView.enableDanmakuDrawingCache(true);

三、创建解析器对象

/** * 创建解析器对象,解析输入流 * @param stream * @return */private BaseDanmakuParser createParser(InputStream stream) {    if (stream == null) {        return new BaseDanmakuParser() {            @Override            protected Danmakus parse() {                return new Danmakus();            }        };    }    ILoader loader = DanmakuLoaderFactory.create(DanmakuLoaderFactory.TAG_BILI);    try {        loader.load(stream);    } catch (IllegalDataException e) {        e.printStackTrace();    }    BaseDanmakuParser parser = new BiliDanmukuParser();    IDataSource<?> dataSource = loader.getDataSource();    parser.load(dataSource);    return parser;}注:DanmakuLoaderFactory.create(DanmakuLoaderFactory.TAG_BILI) //xml解析DanmakuLoaderFactory.create(DanmakuLoaderFactory.TAG_ACFUN) //json文件格式解析

四、自定义弹幕背景和边距

private static class BackgroundCacheStuffer extends SpannedCacheStuffer {    // 通过扩展SimpleTextCacheStuffer或SpannedCacheStuffer个性化你的弹幕样式    final Paint paint = new Paint();    @Override    public void measure(BaseDanmaku danmaku, TextPaint paint) {        danmaku.padding = 10;  // 在背景绘制模式下增加padding        super.measure(danmaku, paint);    }    @Override    public void drawBackground(BaseDanmaku danmaku, Canvas canvas, float left, float top) {        paint.setColor(0x8125309b);  //弹幕背景颜色        canvas.drawRect(left + 2, top + 2, left + danmaku.paintWidth - 2, top + danmaku.paintHeight - 2, paint);    }    @Override    public void drawStroke(BaseDanmaku danmaku, String lineText, Canvas canvas, float left, float top, Paint paint) {        // 禁用描边绘制    }}

五、添加文本弹幕

private void addDanmaku(boolean islive) {    BaseDanmaku danmaku = mContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);    if (danmaku == null || mDanmakuView == null) {        return;    }    danmaku.text = "这是一条弹幕" + System.nanoTime();    danmaku.padding = 5;    danmaku.priority = 0;  //0 表示可能会被各种过滤器过滤并隐藏显示 //1 表示一定会显示, 一般用于本机发送的弹幕    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.borderColor = Color.GREEN; //边框颜色,0表示无边框    mDanmakuView.addDanmaku(danmaku);}

六、添加图文混排弹幕

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);    SpannableStringBuilder spannable = createSpannable(drawable);    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);}/** * 创建图文混排模式 * @param drawable * @return */private SpannableStringBuilder createSpannable(Drawable drawable) {    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);    return spannableStringBuilder;}

七、弹幕的隐藏/显示,暂停/继续

mDanmakuView.hide();mDanmakuView.show();//暂停if (mDanmakuView != null && mDanmakuView.isPrepared()) {        mDanmakuView.pause();    }//继续if (mDanmakuView != null && mDanmakuView.isPrepared() && mDanmakuView.isPaused()) {        mDanmakuView.resume();    }

八、弹幕的定时发送

Boolean b = (Boolean) mBtnSendDanmakus.getTag();timer.cancel();if (b == null || !b) {    mBtnSendDanmakus.setText(R.string.cancel_sending_danmakus);    timer = new Timer();    timer.schedule(new AsyncAddTask(), 0, 1000);    mBtnSendDanmakus.setTag(true); } else {    mBtnSendDanmakus.setText(R.string.send_danmakus);    mBtnSendDanmakus.setTag(false); }Timer timer = new Timer();class AsyncAddTask extends TimerTask {    @Override    public void run() {        for (int i = 0; i < 20; i++) {            addDanmaku(true);            SystemClock.sleep(20);        }    }}

九、创建图文混排的填充适配器

private BaseCacheStuffer.Proxy mCacheStufferAdapter = new BaseCacheStuffer.Proxy() {    private Drawable mDrawable;    /**     * 在弹幕显示前使用新的text,使用新的text     * @param danmaku     * @param fromWorkerThread 是否在工作(非UI)线程,在true的情况下可以做一些耗时操作(例如更新Span的drawblae或者其他IO操作)     * @return 如果不需重置,直接返回danmaku.text     */    @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://www.bilibili.com/favicon.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    }};

十、退出时释放资源

@Overrideprotected void onDestroy() {    super.onDestroy();    if (mDanmakuView != null) {        // dont forget release!        mDanmakuView.release();        mDanmakuView = null;    }}
8 4
原创粉丝点击