Android彈幕實現:基於B站彈幕開源系統(1)

來源:互聯網
上載者:User

標籤:compile   rand   long   1.2   item   round   timer   lsp   phi   

??

Android彈幕實現:基於B站彈幕開源系統(1)

如今的視頻播放,流行在視頻上飄彈幕。這裡面做的相對比較成熟、穩定、使用量較多的彈幕系統,當推B站的彈幕系統,B站的彈幕系統已經作為開源項目在github上,其項目地址:https://github.com/Bilibili/DanmakuFlameMaster
以B站開源的彈幕項目為基礎,現給出一個簡單的例子,實現發送簡單的文本彈幕。
第一步,首先要在Android的build.gradle檔案中引入B站的項目:

repositories {    jcenter()}dependencies {compile ‘com.github.ctiao:DanmakuFlameMaster:0.7.3‘compile ‘com.github.ctiao:ndkbitmap-armv7a:0.7.3‘}


第二步,寫一個布局檔案,引入B站的彈幕view:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <Button        android:id="@+id/show"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="顯示彈幕" />    <Button        android:id="@+id/hide"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="隱藏彈幕" />    <Button        android:id="@+id/sendText"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="發送文本彈幕" />    <Button        android:id="@+id/pause"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="暫停彈幕" />    <Button        android:id="@+id/resume"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="重啟彈幕" />    <master.flame.danmaku.ui.widget.DanmakuView        android:id="@+id/danmakuView"        android:layout_width="match_parent"        android:layout_height="match_parent" /></LinearLayout>


第三步,寫上層Java代碼(該處java代碼改造自B站彈幕github上的demo代碼):

package zhangphil.danmaku;import android.app.Activity;import android.graphics.Color;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import java.util.HashMap;import master.flame.danmaku.danmaku.model.BaseDanmaku;import master.flame.danmaku.danmaku.model.DanmakuTimer;import master.flame.danmaku.danmaku.model.IDisplayer;import master.flame.danmaku.danmaku.model.android.DanmakuContext;import master.flame.danmaku.ui.widget.DanmakuView;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<Integer, Integer> maxLinesPair = new HashMap<>();        maxLinesPair.put(BaseDanmaku.TYPE_SCROLL_RL, 8); // 滾動彈幕最大顯示5行        // 設定是否禁止重疊        HashMap<Integer, Boolean> 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的全部原始碼:

package zhangphil.danmaku;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;        }    }}

Android彈幕實現:基於B站彈幕開源系統(1)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.