ViewGroup的touch事件:dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent

  1. dispatchTouchEvent
    1. 18到24行,如果是ACTION_DOWN事件清除状态,里面有一句
      mFirstTouchTarget null;这个变量很重要,后面会用到
    2. 27到41行,对intercept变量进行处理,这个变量的作用是决定viewgroup要不要对事件进行拦截,为true进行拦截则该group下面的子View不会收到事件。赤裸裸的特权引出来另一个方法onInterceptTouchEvent,此处判断有点多,但是都很必要。一点点看,ACTON_DOWN或者mFirstTouchTarget !null;进入判断,否则intercept=true,disallowIntercept为false且onInterceptTouchEvent(ev)返回true,intercept=true,否则intercept返回false
    3. 57到159,不执行拦截操作
      1. 67行,ACTION_DOWN、ACTION_POINT_DOWN、ACTION_HOVER_MOVE三个动作继续执行,其他动作pass掉
      2. 88行循环遍历,这里注意是从后往前遍历,view排序为屏幕最上层在前面,从后往前遍历的意思就是优先遍历最底层的View,后面会说道首先调用的是window最底层的fragment
      3. 98到110行首先遍历找到符合 childWithAccessibilityFocus条件的子view进行处理,否则重新开始遍历
      4. 112行如果 mFirstTouchTarget不为空,采用后插法构造touchTarger队列
      5. 121行开始递归执行dispatchTransformTouchEvent方法private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,        View child, int desiredPointerIdBits)
        该方法很长,抓住重点下面一句话:如果传入的child==null,执行super.dispatchTouchEvent,super就是view,否则执行child的dispatchTouchEvent,child可能是viewGroup或者view,viewGroup的话则开始递归调用
        if (child == null) {
            handled = super.dispatchTouchEvent(event);
        else {
            handled = child.dispatchTouchEvent(event);
        }
      6. 137行对  mFirstTouchTarget  进行赋值, 
        private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
            final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
            target.next mFirstTouchTarget;
            mFirstTouchTarget = target;
            return target;
        }
      7. 综上:拦截后进入的循环作用就是在TOUCH_DOWN动作中从底层view到顶层遍历执行dispatchTouchEvent方法,知道遍历结束或者某一dispatchTouchEvent返回true,即出现能消费touchDown事件的view,此时给mFirstTouchTarget  赋值,否则mFirstTouchTarget  为null
    4. 162到165,mFirstTouchTarget  =null,执行
      handled = dispatchTransformedTouchEvent(ev, canceled, null,
                              TouchTarget.ALL_POINTER_IDS);
      注意这里第三个参数传的null。表示调用super.dispatchTouchEvent
    5. 166到196开始另一个循环,遍历touchTarget执行dispatchTransformedTouchEvent方法
    6. 至此,大体上解析完毕,因为设计递归还有其他逻辑较多,不容易理解下面举两个例子
    7. 三层View依次重叠放置,其中两个viewGroup,一个view,viewgroup1,viewgroup2,view3假设三个view的touch事件都返回false
      1. 点击发生在view3上(不考虑Activity层的Touch事件传递)
        1. 根据上面第一个循环,首先是最底层的view1进入dispatchTouchEvent,然后执行onInterTouchEvent,然后是递归view2依次执行dispatchTouchEvent和onInterTouchEvent,到view3因为是view层了,执行dispatchTouchEvent,onTouch,onTouchEvent,
        2. 如果view3返回true,代表view3消费了此事件,这时mFirstTouchTarget  的Child为view3,viewgroup2继续向下执行,mFirstTouchTarget  不为null且里面只有一个值,所以
          alreadyDispatchedToNewTouchTarget && target == newTouchTarget成立,不会继续执行。同理view1也不会继续执行
        3. 如果view3返回true,代表view3没有消费此事件,这时mFirstTouchTarget  ==null。后续动作都会进入下面的判断里,所以view2和view1的onTouch和onTouchEvent会依次调用 
          if (mFirstTouchTarget == null) {
              // No touch targets so treat this as an ordinary view.
              handled = dispatchTransformedTouchEvent(ev, canceled, null,
                      TouchTarget.ALL_POINTER_IDS);
          }
        4. 上面可以判断出来如果view1调用了intercept方法则事件不会传递到上层的viewgroup2和view3,如果view3的dispatchTouchEvent返回true,即view3消费了touch事件,则viewgroup1和viewgroup2不会调用后续的touch动作,即动作不再向上传递
        5. 此时如果继续执行TOUCH_UP和TOUCH_MOVE动作,由前面的说明可知,这两个动作不会进入第一个循环,直接进入对mFirstTouchTarget == null的判断。如果mFirstTouchTarget == null即前面的view3没有消费掉touch事件,则viewgroup2和viewgroup3依次执行onTouch和onTouchEvent的TOUCH_MOVE事件,否则只有view3执行
        6. 同理如果ViewGroup2消费了touch事件,则会把view3加入到touchTarger队列中,则viewGroup2和view3两个组件执行后续动作,如果只想让viewGroup2执行后续动作该怎么处理呢,可以把viewgroup2的interceptTouchEvent方法返回true,然后dispatchTouchEvent方法也返回true,即从viewGroup2开始向下拦截向上也拦截
  2. 另一个方法onInterceptTouchEvent 比较简单,返回true代表拦截,返回false代表不拦截,执行拦截时,确保ViewGruop的 disallowIntercept   为false,通过myLinearLayout.requestDisallowInterceptTouchEvent(false); 控制,默认为false 
  3. viewgroup没有提供dispatchTouchEvent的实现,使用的view的

    1. 结论
      1. viewGroup的onInterceptTouchEvent  方法通过拦截控制事件的向上传递
      2. view通过将dispatchTouchEvent返回true控制事件不向下传递
      3. 二者配合完成了安卓事件的冲突处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值