安卓漫漫路之實現簡單的彈幕.
阿新 • • 發佈:2019-02-17
直播和看視訊中越來越火的控制元件---彈幕(Danmaku)
本文即介紹怎樣實現簡單的彈幕效果:咱們使用的是嗶哩嗶哩開源的彈幕效果庫 DanmakuFlameMaster.
必需:首先咱們在專案主工程app/build.gradle中的dependencies閉包中新增如下依賴:
compile 'com.github.ctiao:DanmakuFlameMaster:0.5.3'
這樣我們就將DanmakuFlameMaster庫引入到當前專案中了.
開始展示Demo的程式碼給大家:
首先看咱們的佈局檔案:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#000"> <VideoView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="wrap_content" 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" /> <LinearLayout android:id="@+id/operation_layout" android:layout_width="match_parent" android:layout_height="50dp" android:layout_alignParentBottom="true" android:background="#fff" android:visibility="gone"> <EditText android:id="@+id/edit_text" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" /> <Button android:id="@+id/send" android:layout_width="wrap_content" android:layout_height="match_parent" android:text="傳送" /> </LinearLayout> </RelativeLayout> . 背景色為黑色,承載我是用的Video來播放本地或者網路視訊,DanmakuView即是咱們的彈幕控制元件,LinearLayout內包含輸入框和傳送按鈕.當然這些都是最普通的控制元件,最終的介面當然是由您來設定. 接下來看咱們的MainActivity的程式碼,如下: . import android.graphics.Color; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.text.TextUtils; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.VideoView; import java.util.Random; 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.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 AppCompatActivity { private boolean showDanmaku; //彈幕控制元件 private DanmakuView danmakuView; //DanmakuContext 字型例項 private DanmakuContext danmakuContext; 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控制元件 final VideoView videoView = (VideoView) findViewById(R.id.video_view); //指定好VideoView的本地路徑地址 SD卡根目錄的xxx.mp4檔案 videoView.setVideoPath(Environment.getExternalStorageDirectory() + "/xxx.mp4"); //訪問網路視訊 //Uri uri = Uri.parse("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"); //設定視訊控制器 //videoView.setMediaController(new MediaController(this)); //設定視訊路徑 // videoView.setVideoURI(uri); //開始播放 videoView.start(); new android.os.Handler().postDelayed(new Runnable() { @Override public void run() { videoView.pause(); } }, 0); //初始化彈幕控制元件 danmakuView = (DanmakuView) findViewById(R.id.danmaku_view); //預設為true 在模擬器上執行有問題 danmakuView.enableDanmakuDrawingCache(true); //看原始碼得知是一個介面 怎麼實現還是要咱們去重寫其中的方法 danmakuView.setCallback(new DrawHandler.Callback() { @Override public void prepared() { //把變數置為 true showDanmaku = true; //開始執行彈幕控制元件 danmakuView.start(); //隨機生成一些彈幕內容以供測試 generateSomeDanmaku(); } @Override public void updateTimer(DanmakuTimer timer) { } @Override public void danmakuShown(BaseDanmaku danmaku) { } @Override public void drawingFinished() { } }); //呼叫 DanmakuContext.create() 完成DanmakuContext的例項化. danmakuContext = DanmakuContext.create(); danmakuView.prepare(parser, danmakuContext); //初始化含有輸入框和按鈕的線性佈局 final LinearLayout operationLayout = (LinearLayout) findViewById(R.id.operation_layout); //初始化傳送按鈕 final Button send = (Button) findViewById(R.id.send); //輸入框輸入內容 final EditText editText = (EditText) findViewById(R.id.edit_text); //適時的讓輸入框顯現或隱藏 danmakuView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (operationLayout.getVisibility() == View.GONE) { operationLayout.setVisibility(View.VISIBLE); } else { operationLayout.setVisibility(View.GONE); } } }); //傳送按鈕的點選事件 send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String content = editText.getText().toString(); if (!TextUtils.isEmpty(content)) { //因為是自己的內容,所以傳一個true過去,方法內部會判斷這個變數 addDanmaku(content, true); //再把輸入框置為空 editText.setText(""); } } }); //獲取到窗體的頂級父類並設定狀態列的顯示隱藏 getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() { @Override public void onSystemUiVisibilityChange(int visibility) { if (visibility == View.SYSTEM_UI_FLAG_VISIBLE) { //顯示狀態列,Activity不全屏顯示 onWindowFocusChanged(true); } } }); } /** * 向彈幕View中新增一條彈幕 * * @param content 彈幕的具體內容 * @param withBorder 彈幕是否有邊框 */ private void addDanmaku(String content, boolean withBorder) { //BaseDanmaku 您可以點選進入檢視原始碼實現 // 彈幕的相關設定:彈幕優先順序 顏色 時長 文字 Z軸 Y軸 陰影 描邊 // 下劃線 內邊距 寬度 高度 存活時間 是否是直播彈幕 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()); //顯示時長 偏移時間 //如果是true 證明是自己的彈幕,那麼就可以更改自己想要的顏色了 if (withBorder) { danmaku.borderColor = Color.GREEN; } //呼叫底層程式碼 把彈幕內容新增到LinkedList<Long> mDrawTimes; danmakuView.addDanmaku(danmaku); } /** * 隨機生成一些彈幕內容以供測試 */ private void generateSomeDanmaku() { new Thread(new Runnable() { @Override public void run() { while (showDanmaku) { int time = new Random().nextInt(300); String content = "" + time + time; addDanmaku(content, false); 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//表示Activity正在停止. protected void onPause() { super.onPause(); //如果彈幕控制元件不為空 && 彈幕控制元件的執行緒還存活 if (danmakuView != null && danmakuView.isPrepared()) { //暫停執行彈幕控制元件 danmakuView.pause(); } } @Override//表示Activity前臺並可與使用者互動. protected void onResume() { super.onResume(); if (danmakuView != null && danmakuView.isPrepared() && danmakuView.isPaused()) { danmakuView.resume(); } } @Override//表示Activity即將被銷燬. protected void onDestroy() { super.onDestroy(); //把變數置為false showDanmaku = false; //如果彈幕控制元件還存在.呼叫release(); 底層呼叫stop(),並把底層的LinkedList<Long> mDrawTimes 置為空; if (danmakuView != null) { danmakuView.release(); danmakuView = null; } } @Override//都說這個函式才會使使用者可以與應用真正開始進行互動. public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); //看了底層後得知 Build.VERSION.SDK_INT == 20 ; if (hasFocus && Build.VERSION.SDK_INT >= 19) { View decorView = getWindow().getDecorView(); decorView.setSystemUiVisibility( //這個標誌來幫助你的應用維持一個穩定的佈局. View.SYSTEM_UI_FLAG_LAYOUT_STABLE //Activity全屏顯示,但狀態列不會被隱藏覆蓋,狀態列依然可見,Activity頂端佈局部分會被狀態遮住。 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION //ctivity全屏顯示,但狀態列不會被隱藏覆蓋,狀態列依然可見,Activity頂端佈局部分會被狀態遮住. | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN //ctivity全屏顯示,但狀態列不會被隱藏覆蓋,狀態列依然可見,Activity頂端佈局部分會被狀態遮住. | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION //Activity全屏顯示,且狀態列被隱藏覆蓋掉. | View.SYSTEM_UI_FLAG_FULLSCREEN //安卓4.4 新增. | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); } } }
如上,在安卓裝置上,一個簡單的彈幕Demo就可以實現了.
如有問題請多指正,您的指正使我更正確的前行.