第一阶段的主要工作有俩:一是在第6行的resetTouchState方法中完成了对FLAG_DISALLOW_INTERCEPT标记的重置;二是第5行的cancelAndClearTouchTargets方法会清除当前MotionEvent的touch target。关于FLAG_DISALLOW_INTERCEPT标记和touch target,在下文会有相关说明。
第二阶段的主要工作是决定当前ViewGroup是否拦截本次的touch事件,主要代码如下:
//Check for interception.
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWM || mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); //restore action in case it was changed
} else {
intercepted = false;
}
} else {
//There are no touch targets and this action is not an initial down so this view group continues to intercept touches.
intercept =true;
}
由以上代码我们可以知道,当一个touch事件被传递到ViewGroup时,会先判断这个touch事件的动作是否是ACTION_DOWN,如果这个事件是ACTION_DOWN或者mFirstTouchTarget不为null,就会根据FLAG_DISALLOW_INTERCEPT标记决定是否拦截这个touch事件。那么mFirstTouchTarget是什么呢?当touch事件被ViewGroup的子View成功处理时,mFirstTouchTarget就会被赋值为成功处理touch事件的View,也就是上面提高的touch target。
总结一下上述代码的流程:在子View不干预ViewGroup的拦截的情况下(上述代码中的disallowIntercept为false),若当前事件为ACTION_DOWN或者mFirstTouchTarget不为空,则会调用ViewGroup的onInterceptTouchEvent方法来决定最终是否拦截此事件;否则(没有TargetView并且此事件不是ACTION_DOWN),当前ViewGroup就拦截下此事件。 一旦ViewGroup拦截了某次touch事件,那么mFirstTouchTarget就不会被赋值,因此当再有ACTION_MOVE或是ACTION_UP传递到该ViewGroup时,mTouchTarget就为null,所以上述代码第3行的条件就为false,ViewGroup会拦截下来。由此可得到的结论是:一旦ViewGroup拦截了某次事件,则同一事件序列中的剩余事件也会它默认被拦截而不会再询问是否拦截(即不会再调用onInterceptTouchEvent)。
这里存在一种特殊情形,就是子View通过requestDisallowInterceptTouchEvent方法设置父容器的FLAG_DISALLOW_INTERCEPT为true,这个标记指示是否不允许父容器拦截,为true表示不允许。这样做能够禁止父容器拦截除ACTION_DOWN以外的所有touch事件。之所以不能够拦截ACTION_DOWN事件,是因为每当ACTION_DOWN事件到来时,都会重置FLAG_DISALLOW_INTERCEPT这个标记位为默认值(false),所以每当开始一个新touch事件序列(即到来一个ACTION_DOWN动作),都会通过调用onInterceptTouchEven询问ViewGroup是否拦截此事件。当ACTION_DOWN事件到来时,重置标记位的工作是在上面的第一阶段完成的。










