ViewGroup#dispatchTouchEvent细节分析

     if (actionMasked == MotionEvent.ACTION_DOWN) {
                // Throw away all previous state when starting a new touch gesture.
                // The framework may have dropped the up or cancel event for the previous gesture
                // due to an app switch, ANR, or some other state change.
                cancelAndClearTouchTargets(ev);
                resetTouchState();
            }
Down事件会重置全部的标记位,这个很关键,可以理解为游戏重开
final boolean intercepted;
            if (actionMasked == MotionEvent.ACTION_DOWN
                    || 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.
                intercepted = true;
            }
这段代码解释了为什么DOWN事件如果被拦截,那么后续的事件子View都不会收到的原理。在DOWN事件的时候子view能否有机会消费事件完全取决于父view的
onInterceptTouchEvent方法,因为Down事件会重置全部的标记位,因此final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;一直会是false,所以就会执行
intercepted = onInterceptTouchEvent(ev);如果此时intercepted返回了true,mFirstTouchTarget就会是null,那么后续的move、up事件在进入的时候就会直接执行
else {
// There are no touch targets and this action is not an initial down
// so this view group continues to intercept touches.
intercepted = true;
}这个逻辑。那final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0什么时候才会生效呢?很明显,最少也需要DOWN事件交给子View的时候设置requestDisallowInterceptTouchEvent(true)
来要求父view不拦截后续的move、up事件,父view才会在后续的move、up不执行onInterceptTouchEvent而是执行intercepted = false;才有可能把后续事件交给子view。这个细节直接决定在自定义view的时候如何在
dispatchTouchEvent、onInterceptTouchEvent中的代码逻辑如何写。

分析一下拦截事件:
如果事件被拦截了mFirstTouchTarget就会是null,就会执行handled = dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS); 其实就是View的dispatchTouchEvent方法然后执行自己的消费方法。
如果事件不拦截:还是在Down事件的寻找消费的子view,如果没找到同上逻辑。如果找到了mFirstTouchTarget就不为空,后需事件还是执行是否拦截的逻辑,如果拦截,逻辑同上。如果不拦截交给子view的dispatchTransformedTouchEvent处理。

无论是当前父view消费还是其子view消费事件都是次view处理了,就不会朝上级view返回了。
    ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

            if (!result && onTouchEvent(event)) {
                result = true;
            }
onTouchEvent的执行收到onTouch返回值的影响,如果onTouch的返回值是true,那么onTouchEvent就不会执行,因为onClick和onLongClick都是在onTouchEvent方法里面。所以。。。


 



 

posted @ 2026-01-04 15:15  lianzhen  阅读(2)  评论(0)    收藏  举报