滑动冲突外部拦截法源码分析

为了解决滑动冲突可以采用外部拦截法,就是重写父布局的onIntercepteTouchEvent方法:ACTION_DOWN 不拦截,ACTION_MOVE,达到父元素滑动条件就拦截,达不到就不拦截

 override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        var intercpted = false
        var x = ev?.x
        var y = ev?.y
        when(ev?.action){
           MotionEvent.ACTION_DOWN->{
               intercpted = false
           }
           MotionEvent.ACTION_MOVE->{
               if(满足父元素的条件){
                   intercepted = true
               }else{
                   intercepted = false
               }
           }
           MotionEvent.ACTION_UP->{
               intercpted = false
           }
        }

        Log.e("gacmy","ViewGroup2 onInterceptTouchEvent:${intercpted}")
        return intercpted
    }

分析1:为什么ACTION_DOWN 不拦截?


查看ViewGroup dispatchTouchEvent源码可以知道ACTION_DOWN拦截以后,后续事件的派发都不会再传递给子View

分析2,如果ACTION_MOVE 满足父布局的滑动条件,拦截一次之后,再没有触发下一次ACTION_DOWN事件情况下,即使再次满足子布局的滑动条件,子布局也不会再次受到任何事件。

 if (!canceled && !intercepted) {
    ...
    这里是进行ACTION_DOWN事件派发的操作,
    如果intercepted 是true的话,这里就不会再执行
    ...
 }
 //如果ACTION_DWON事件被拦截,则子View一定不会存在mFirstTouchTarget链表中
 //这里进行ACTION_MOVE ACTION_UP事件的派发
 //ViewGroup只有一个子View ACTION_DOWN被拦截之后,mFirstTouchTarget == null
 //后续事件都只会传递给父布局自己的onTouch事件里面
  if (mFirstTouchTarget == null) {
                
        handled = dispatchTransformedTouchEvent(ev, canceled, null,
                TouchTarget.ALL_POINTER_IDS);
   } else {
         TouchTarget target = mFirstTouchTarget;
         //这里处理ACTION_MOVE 事件和ACTION_UP事件
        while (target != null) {
        //每一次 dispatchTouchEvent执行的时候     newTouchTarget = null
          final TouchTarget next = target.next;
          if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
                        handled = true;
          } else {
             //ACTION_MOVE 滑动父布局intercepted返回true,cancelChild这里返回true
             final boolean cancelChild = resetCancelNextUpFlag(target.child)
                                || intercepted;
             if(dispatchTransformedTouchEvent(ev, cancelChild,target.child, target.pointerIdBits)) {
                            handled = true;
              }
            //cancelChild = true
            //子布局的TouchTarget会在链表中被删除。
            //父布局只有一个子View的情况下,mFirstTouchTarget = null
            //下一次即使满足子布局的滑动条件,intercepted = false。也不会在给他传递任何事件了。
            
            if (cancelChild) {
                 if (predecessor == null) {
                     mFirstTouchTarget = next;
                 } else {
                     predecessor.next = next;
                 }
                  target.recycle();
                  target = next;
                  continue;
            }
        }
            predecessor = target;
          target = next;
        }

       
   }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值