实现简单的弹幕

第一步,首先要在Android的build.gradle文件中引入B站的项目:

repositories {

    jcenter()

}

导入依赖

compile 'com.github.ctiao:DanmakuFlameMaster:0.7.3'

compile 'com.github.ctiao:ndkbitmap-armv7a:0.7.3'

第二步,写一个布局文件,引入B站的弹幕view:

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:orientation="vertical">


        android:id="@+id/show"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="显示弹幕" />


        android:id="@+id/hide"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="隐藏弹幕" />


        android:id="@+id/sendText"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="发送文本弹幕" />


        android:id="@+id/pause"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="暂停弹幕" />


        android:id="@+id/resume"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="重启弹幕" />


        android:id="@+id/danmakuView"

        android:layout_width="match_parent"

        android:layout_height="match_parent" />

第三步,写上层Java代码(该处java代码改造自B站弹幕github上的demo代码):

public class MainActivity extends Activity {

    private DanmakuView mDanmakuView;

    private DanmakuContext mContext;

    private AcFunDanmakuParser mParser;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        mDanmakuView = (DanmakuView) findViewById(R.id.danmakuView);

        Button show = (Button) findViewById(R.id.show);

        Button hide = (Button) findViewById(R.id.hide);

        Button sendText = (Button) findViewById(R.id.sendText);

        Button pause = (Button) findViewById(R.id.pause);

        Button resume = (Button) findViewById(R.id.resume);

        show.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                mDanmakuView.show();

            }

        });

        hide.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                mDanmakuView.hide();

            }

        });

        sendText.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                //每点击一次按钮发送一条弹幕

                sendTextMessage();

            }

        });

        pause.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                mDanmakuView.pause();

            }

        });

        resume.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                mDanmakuView.resume();

            }

        });

        init();

    }

    private void init() {

        mContext = DanmakuContext.create();

        // 设置最大显示行数

        HashMap maxLinesPair = new HashMap<>();

        maxLinesPair.put(BaseDanmaku.TYPE_SCROLL_RL, 8); // 滚动弹幕最大显示5行

        // 设置是否禁止重叠

        HashMap overlappingEnablePair = new HashMap<>();

        overlappingEnablePair.put(BaseDanmaku.TYPE_SCROLL_RL, true);

        overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_TOP, true);

        mContext.setDanmakuStyle(IDisplayer.DANMAKU_STYLE_STROKEN, 10) //描边的厚度

                .setDuplicateMergingEnabled(false)

                .setScrollSpeedFactor(1.2f) //弹幕的速度。注意!此值越小,速度越快!值越大,速度越慢。// by phil

                .setScaleTextSize(1.2f)  //缩放的值

                //.setCacheStuffer(new SpannedCacheStuffer(), mCacheStufferAdapter) // 图文混排使用SpannedCacheStuffer

//        .setCacheStuffer(new BackgroundCacheStuffer())  // 绘制背景使用BackgroundCacheStuffer

                .setMaximumLines(maxLinesPair)

                .preventOverlapping(overlappingEnablePair);

        mParser = new AcFunDanmakuParser();

        mDanmakuView.prepare(mParser, mContext);

        //mDanmakuView.showFPS(true);

        mDanmakuView.enableDanmakuDrawingCache(true);

        if (mDanmakuView != null) {

            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) {

                    Log.d("弹幕文本", "danmakuShown text=" + danmaku.text);

                }

                @Override

                public void prepared() {

                    mDanmakuView.start();

                }

            });

        }

    }

    private void sendTextMessage() {

        addDanmaku(true);

    }

    private void addDanmaku(boolean islive) {

        BaseDanmaku danmaku = mContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);

        if (danmaku == null || mDanmakuView == null) {

            return;

        }

        danmaku.text = "zhangphil @ csdn :" + System.currentTimeMillis();

        danmaku.padding = 5;

        danmaku.priority = 0;  // 可能会被各种过滤器过滤并隐藏显示

        danmaku.isLive = islive;

        danmaku.setTime(mDanmakuView.getCurrentTime() + 1200);

        danmaku.textSize = 20f * (mParser.getDisplayer().getDensity() - 0.6f); //文本弹幕字体大小

        danmaku.textColor = getRandomColor(); //文本的颜色

        danmaku.textShadowColor = getRandomColor(); //文本弹幕描边的颜色

        //danmaku.underlineColor = Color.DKGRAY; //文本弹幕下划线的颜色

        danmaku.borderColor = getRandomColor(); //边框的颜色

        mDanmakuView.addDanmaku(danmaku);

    }

    @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;

        }

    }

    /**

    * 从一系列颜色中随机选择一种颜色

    *

    * @return

    */

    private int getRandomColor() {

        int[] colors = {Color.RED, Color.YELLOW, Color.BLUE, Color.GREEN, Color.CYAN, Color.BLACK, Color.DKGRAY};

        int i = ((int) (Math.random() * 10)) % colors.length;

        return colors[i];

    }

}

第四步 :使用了一个叫做AcFunDanmakuParser的弹幕parser,这个解析器得自己写,自己基于json数据格式实现。该类写好基本就可以拿来稳定使用,现给出AcFunDanmakuParser的全部源代码:

import org.json.JSONArray;

import org.json.JSONException;

import org.json.JSONObject;

import master.flame.danmaku.danmaku.model.BaseDanmaku;

import master.flame.danmaku.danmaku.model.android.Danmakus;

import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;

import master.flame.danmaku.danmaku.parser.android.JSONSource;

import master.flame.danmaku.danmaku.util.DanmakuUtils;

/**

* Created by phil on 2017/3/29.

*/

public class AcFunDanmakuParser extends BaseDanmakuParser {

    public AcFunDanmakuParser() {

    }

    public Danmakus parse() {

        if (this.mDataSource != null && this.mDataSource instanceof JSONSource) {

            JSONSource jsonSource = (JSONSource) this.mDataSource;

            return this.doParse(jsonSource.data());

        } else {

            return new Danmakus();

        }

    }

    private Danmakus doParse(JSONArray danmakuListData) {

        Danmakus danmakus = new Danmakus();

        if (danmakuListData != null && danmakuListData.length() != 0) {

            for (int i = 0; i < danmakuListData.length(); ++i) {

                try {

                    JSONObject e = danmakuListData.getJSONObject(i);

                    if (e != null) {

                        danmakus = this._parse(e, danmakus);

                    }

                } catch (JSONException var5) {

                    var5.printStackTrace();

                }

            }

            return danmakus;

        } else {

            return danmakus;

        }

    }

    private Danmakus _parse(JSONObject jsonObject, Danmakus danmakus) {

        if (danmakus == null) {

            danmakus = new Danmakus();

        }

        if (jsonObject != null && jsonObject.length() != 0) {

            for (int i = 0; i < jsonObject.length(); ++i) {

                try {

                    String c = jsonObject.getString("c");

                    String[] values = c.split(",");

                    if (values.length > 0) {

                        int type = Integer.parseInt(values[2]);

                        if (type != 7) {

                            long time = (long) (Float.parseFloat(values[0]) * 1000.0F);

                            int color = Integer.parseInt(values[1]) | -16777216;

                            float textSize = Float.parseFloat(values[3]);

                            BaseDanmaku item = this.mContext.mDanmakuFactory.createDanmaku(type, this.mContext);

                            if (item != null) {

                                item.setTime(time);

                                item.textSize = textSize * (this.mDispDensity - 0.6F);

                                item.textColor = color;

                                item.textShadowColor = color <= -16777216 ? -1 : -16777216;

                                DanmakuUtils.fillText(item, jsonObject.optString("m", "...."));

                                item.index = i;

                                item.setTimer(this.mTimer);

                                danmakus.addItem(item);

                            }

                        }

                    }

                } catch (JSONException var13) {

                } catch (NumberFormatException var14) {

                }

            }

            return danmakus;

        } else {

            return danmakus;

        }

    }

}

详情:网址:https://blog.csdn.net/zhangphil/article/details/68067100

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,245评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,749评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,960评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,575评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,668评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,670评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,664评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,422评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,864评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,178评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,340评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,015评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,646评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,265评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,494评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,261评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,206评论 2 352

推荐阅读更多精彩内容