android 弹幕框架DanmakuFlameMaster,解决 控制Ui和弹幕点击的问题.

柳宪
2023-12-01

android 直播弹幕,在使用之前,如果有人对DanmakuFlameMaster还不了解怎么用的话,可以参考郭霖的这个博客郭霖的弹幕功能实现的博客.
但是在这里我还是建议大家直接看DanmakuFlameMaster的官方Demo,因为版本的迭代,而上面这篇博客某些地方Api已经过时.

  • 下面借助郭大神博客的一张图:
  • 在这样图中我们可以看到VoideView在最底层 -> 弹幕VIew -操作View
  • VoideView :只有播放视频的api,毫无交互操作
  • 弹幕View : 显示弹幕view, 弹幕有可能需要点击效果
  • 操作View : 双击:播放/暂停 , 单点:显示/隐藏 整个操作的VIew , 左上滑 +亮度 , 左滑 +声音.
    那么问题来了,弹幕需要点击,那么就会拦截按下, 操作View也需要点击和双击,也会拦截按下.

下面就是解决这个问题的方法: 思路:既然两个都需要拦截点击事件,那么就直接让两个View的setOnTouchListener合并成一个setOnTouchListener,但是这里有两个问题:

  • 合并到谁: 合并到DanmakuFlameMaster库的DanmakuView
  • DanmakuFlameMaster是用implementation'com.github.ctiao:DanmakuFlameMaster:0.9.25'依赖的,怎么样来解决框架内部的setOnTouchListener事件呢? 答案:反射.
    /*
    master.flame.danmaku.ui.widget.DanmakuView 的源码,可以看到使用自定义TouchHelper,源码里面直接拦截了
    */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean isEventConsumed = mTouchHelper.onTouchEvent(event);
        if (!isEventConsumed) {
            return super.onTouchEvent(event);
        }
        return isEventConsumed;
    }
    /*master.flame.danmaku.ui.widget.DanmakuTouchHelper,可以看到源码里面onDown方法只要设置OnDanmakuClickListener
    ,那么就返回true,这样是有问题的,不管是把DanmakuView覆盖在VoideControlBox上,还是在VoideControlBox  
    下都被令另外一个View 的事件出问题.*/
    private final android.view.GestureDetector.OnGestureListener mOnGestureListener = new GestureDetector.SimpleOnGestureListener() {
     @Override
     public boolean onDown(MotionEvent event) {
         if (danmakuView != null) {
             IDanmakuView.OnDanmakuClickListener onDanmakuClickListener = danmakuView.getOnDanmakuClickListener();
             if (onDanmakuClickListener != null) {
                 mXOff = danmakuView.getXOff();
                 mYOff = danmakuView.getYOff();
                 return true;
             }
         }
         return false;
     }
     //....省略了部分代码
    };
    
    /**
    解决办法,反射获取mTouchHelper,模拟onTouchEvent();
    然后把自己的VoideControlBox的一些事件也交给setOnTouchListener来处理,下面请看代码
    */
    DanmakuTouchHelper mTouchHelper;
    try {
        Field field = mPlayDanmakuView.getClass().getDeclaredField("mTouchHelper");
        field.setAccessible(true);
        Object obj = field.get(mPlayDanmakuView);
        if (obj instanceof DanmakuTouchHelper) {
            mTouchHelper = (DanmakuTouchHelper) obj;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    //mPlayDanmakuView 这是弹幕View 的对象.
    mPlayDanmakuView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            //ControlBox 的事件处理返回
            boolean isEvent = mPlayerHelper.mGestureDetector.onTouchEvent(event);
            boolean isEventConsumed = false;
            // 如果反射拿到了mTouchHelper ,执行onTouchEvent方法.
            if (mTouchHelper != null) {
                isEventConsumed = mTouchHelper.onTouchEvent(event);
            }
            //如果是ControlBox返回为true 或者是弹幕事件返回为true, 消费该事件
            if (isEvent || isEventConsumed) {
                return true;
            }
            // 处理手势结束, 取消一些如音量View,亮度View
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_UP:
                    mPlayerHelper.endGesture();
                    break;
            }
            return true;
        }
    });
    
    
    - 好了,如果有朋友没懂的可以加我QQ 97149859咨询.
    
复制代码
 类似资料: