1.Activity
Window(PhoneWindow)->DecorView(FrameLayout)->ViewGroup
dispatchTouchEvent
- return true/false Touch事件被消费
- return super 正常分发Touch事件->ViewGroup.dispatchTouchEvent
Window.superDispatchTouchEvent
DecorView.superDispatchTouchEvent
onTouchEvent
- return true Touch事件被消费
2.ViewGroup
mFirstTouchTarget(TouchTarget)
事件被消费不为null- child(View) 被Touch的子View对象
- pointerIdBits(int) 被触摸的ID
- next(TouchTarget)下一级触摸目标
requestDisallowInterceptTouchEvent(boolean disallowIntercept)
- ture 不允许拦截
- false 允许拦截
-
dispatchTouchEvent
- return false 不消费事件,往回(上级的onTouchEvent)传递,后续系列事件不再传递到此View
- return true 事件被消费
- return super 结果由onTouchEvent决定
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; }
- 检查是否需要ViewGroup拦截Touch事件
- ACTION_DOWN
- mFirstTouchTarget!=null 表示ViewGroup没有拦截Touch事件并且子View消费了Touch
- mFirstTouchTarget==null 表示ViewGroup拦截了Touch事件或者虽然ViewGroup没有拦截Touch事件但是子View也没有消费Touch。总之,此时需要ViewGroup自身处理Touch事件
if (!canceled && !intercepted) { ... //此事件为Down事件或者第二个手指触碰屏幕事件或者为鼠标事件,此处只研究Donw事件 if (actionMasked == MotionEvent.ACTION_DOWN || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { ... if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { //1 ... } } } ... if (mFirstTouchTarget == null) { // 2 handled = dispatchTransformedTouchEvent(ev, canceled, null, TouchTarget.ALL_POINTER_IDS); } else { ... //3 if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) { handled = true; } else { ... if (dispatchTransformedTouchEvent(ev, cancelChild, target.child, target.pointerIdBits)) { handled = true; } ... } ... }
dispatchTransformedTouchEvent
- 事件DOWN且未被拦截会调用1,分发给孩子View处理
- 事件未被孩子View消费会调用2,给当前onTouchEvent处理,后续不往下分发
- Down事件被孩子View消费,后续事件会调用3;Down事件时不会被调用
if (child == null) { handled = super.dispatchTouchEvent(event); } else { handled = child.dispatchTouchEvent(event); }
-
onInterceptTouchEvent
- return false/super不拦截
- return true拦截mFirstTouchTarget==null,触摸事件交给当前ViewGroup的onTouchEvent
-
onTouchEvent
- return super/false 不消费事件,往回传递(上级的onTouchEvent),后续系列事件不再传递到此ViewGroup
- return true 事件被消费
3.View
dispatchTouchEvent
if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { result = true; } if (!result && onTouchEvent(event)) { result = true; }
- OnTouchListener不为空,且onTouch返回true,则事件被消费,不会传递至OnTouchEvent
- return false 不消费事件,往回传递,后续系列事件不再传递到此View
- return true 事件被消费
- return super 结果由OnTouchListener.onTouch/onTouchEvent决定
onTouchEvent
- return super/false 不消费事件,往回传递,后续系列事件不再传递到此View
- return true 事件被消费
面试题
事件传递是由 Activity_diapatchTouchEvent——>Window:PhoneWindow_diapatchTouchEvent——>DecorView:FrameLayout_diapatchTouchEvent——>ViewGroup_diapatchTouchEvent(可通过拦截方法onInterceptTouchEvent停止传递)——...——>View_diapatchTouchEvent->View_onTouchEvent->ViewGroup_onTouchEvent-...->Activity_onTouchEvent。
通俗来说就是Activity收到事件,询问子View能否消费,子View为ViewGroup情况下,判断其是否拦截:
- 若拦截交给自己的onTouchEvent消费;
- 若未拦截,则继续询问到具体子View为止,最后交给View的onTouchEvent消费;
- onTouchEvent:事件被消费,事件结束;事件未被消费,返回给上级onTouchEvent消费,往后序列事件将不再传递给该View处理