弹幕功能实现

先看郭霖大神播客
http://blog.youkuaiyun.com/sinyu890807/article/details/51933728
我的Demo只是在此基础上
1、加了隐藏和显示的两个按钮
2、点击send后关闭小键盘
详细扩展功能可看
http://m.blog.youkuaiyun.com/article/details?id=51056646
和官方sample中的MainActivity中代码

哔哩哔哩开源的弹幕效果库:DanmakuFlameMaster
https://github.com/Bilibili/DanmakuFlameMaster

备注:
这个Demo演示的是自己随机生成的弹幕,如果在真实的app中,要基于app中的即时消息模块的聊天室,要获得聊天室中的成员发送的消息内容、消息时间(根据消息时间确定弹幕出现在屏幕上的时间)等,聊天室中每当有消息发送,调用添加弹幕的方法向弹幕view中添加弹幕

布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.sign.danmutest.MainActivity">

    <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/danku_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <LinearLayout
        android:id="@+id/ll"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal"
        android:visibility="gone"
        >
        <Button
            android:id="@+id/btnHide"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="hide"
            />
        <Button
            android:id="@+id/btnShow"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="show"
            />
        <EditText
            android:id="@+id/edtText"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"
            />
        <Button
            android:id="@+id/btnSend"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="send"
            />
    </LinearLayout>
</RelativeLayout>

代码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private VideoView videoView;
    private DanmakuView danmakuView;
    private LinearLayout ll ;
    private EditText edtText;
    private Button btnHide,btnShow,btnSend;

    private boolean showDanmaku;

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

        ll = (LinearLayout) findViewById(R.id.ll);//操作栏
        edtText = (EditText) findViewById(R.id.edtText);//输入框
        btnHide = (Button) findViewById(R.id.btnHide);//隐藏按钮
        btnShow = (Button) findViewById(R.id.btnShow);//显示按钮
        btnSend = (Button) findViewById(R.id.btnSend);//发送
        btnHide.setOnClickListener(this);
        btnShow.setOnClickListener(this);
        btnSend.setOnClickListener(this);

        videoView = (VideoView) findViewById(R.id.video_view);
//        播放本地的abc.mp4
        videoView.setVideoPath(Environment.getExternalStorageDirectory() + "/abc.mp4");
        videoView.start();

        danmakuView = (DanmakuView) findViewById(R.id.danku_view);
        danmakuView.enableDanmakuDrawingCache(true);//提升绘制效率
        danmakuView.setCallback(new DrawHandler.Callback() {
            @Override
            public void prepared() {
                showDanmaku = true;
                danmakuView.start();
                generateSomeDanmaku();
            }

            @Override
            public void updateTimer(DanmakuTimer timer) {

            }

            @Override
            public void drawingFinished() {

            }
        });

//        DanmakuContext可以用于对弹幕的各种全局配置进行设定,如设置字体、设置最大显示行数等
        danmakuContext = DanmakuContext.create();
//        有了DanmakuContext和BaseDanmakuParser,接下来我们就可以调用DanmakuView的prepare()方法来进行准备,
//          准备完成后会自动调用刚才设置的回调函数中的prepared()方法
        danmakuView.prepare(parser, danmakuContext);

//        点击danmukuView,如果下方的操作栏处于显示,则设置为gone,反之。。。
        danmakuView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(ll.getVisibility() == View.VISIBLE){
                    ll.setVisibility(View.GONE);
                }else{
                    ll.setVisibility(View.VISIBLE);
                }
            }
        });

//        由于系统输入法弹出的时候会导致焦点丢失,从而退出沉浸式模式,因此这里还对系统全局的UI变化进行了监听,保证程序一直可以处于沉浸式模式。
        getWindow().getDecorView().setOnSystemUiVisibilityChangeListener (new View.OnSystemUiVisibilityChangeListener() {
            @Override
            public void onSystemUiVisibilityChange(int visibility) {
                if (visibility == View.SYSTEM_UI_FLAG_VISIBLE) {
                    onWindowFocusChanged(true);
                }
            }
        });
    }

    //    用于向DanmakuView中添加一条弹幕消息
//    withBorder参数,这个参数用于指定弹幕消息是否带有边框,这样才好将自己发送的弹幕和别人发送的弹幕进行区分
    private void addDanmaku(String content, boolean withBorder) {
        BaseDanmaku danmaku = danmakuContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
        danmaku.text = content;
        danmaku.padding = 5;
        danmaku.textSize = sp2px(20);
        danmaku.textColor = Color.WHITE;
        danmaku.time = danmakuView.getCurrentTime();

        if (withBorder) {
            danmaku.borderColor = Color.BLUE;//边框颜色
            danmaku.textColor = Color.YELLOW;//文字颜色
        }

        danmakuView.addDanmaku(danmaku);
    }

    //   随机生成一些弹幕以供测试
    private void generateSomeDanmaku() {
        new Thread(){
            @Override
            public void run() {
                super.run();
                while(showDanmaku) {
                    int time = new Random().nextInt(300);
                    String content = "" + time + time;
                    addDanmaku(content, false);//添加随机生成的弹幕,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
    protected void onPause() {
        super.onPause();
        if (danmakuView != null && danmakuView.isPrepared()) {
            danmakuView.pause();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (danmakuView != null && danmakuView.isPrepared() && danmakuView.isPaused()) {
            danmakuView.resume();
        }
    }

//    退出时释放资源
    @Override
    protected void onDestroy() {
        super.onDestroy();
        showDanmaku = false;
        if (danmakuView != null) {
            danmakuView.release();
            danmakuView = null;
        }
    }

//    设置界面为沉浸式
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (hasFocus && Build.VERSION.SDK_INT >= 19) {
            View decorView = getWindow().getDecorView();
            decorView.setSystemUiVisibility(
                    View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                            | View.SYSTEM_UI_FLAG_FULLSCREEN
                            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
        }
    }

    @Override
    public void onClick(View v) {
//        弹幕view不为空,且弹幕view
        if(danmakuView != null && danmakuView.isPrepared()){
            switch (v.getId()){
                case R.id.btnHide:
//                    隐藏弹幕
                    danmakuView.hide();
                    break;
                case R.id.btnShow:
//                    显示弹幕
                    danmakuView.show();
                    break;
                case R.id.btnSend:
                    String content = edtText.getText().toString();
                    if(!TextUtils.isEmpty(content)){
                        addDanmaku(content,true);//发送自己的弹幕,true为自己发送的弹幕,可以根据此标记设置字体颜色及边框
                        edtText.setText("");//让输入框为空
                    }

                    //getCurrentFocus()是获取当前activity中获得焦点的view
                    View v1 = getCurrentFocus();
                    if(v1 != null){
                        //隐藏软键盘
                        ((InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(v.getWindowToken(),InputMethodManager.HIDE_NOT_ALWAYS);
                    }
                    break;
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值