diff --git a/blogs/Android/Framework/深入理解 Android 内核设计思想/View 事件分发.md b/blogs/Android/Framework/深入理解 Android 内核设计思想/View 事件分发.md index e7cd919..9920ff7 100644 --- a/blogs/Android/Framework/深入理解 Android 内核设计思想/View 事件分发.md +++ b/blogs/Android/Framework/深入理解 Android 内核设计思想/View 事件分发.md @@ -52,3 +52,58 @@ public boolean dispatchTouchEvent (MotionEvent event) { #### ViewGroup 中 TouchEvent 的投递流程 +ViewGroup 因为涉及对子 View 的处理,其派发流程没有 View 那么简单直接,它重写了 dispatchTouchEvent 方法: + +```java +public boolean dispatchTouchEvent(MotionEvent ev) { + boolean handled = false; + if (onFilterTouchEventForSecurity(ev)) { + final int action = ev.getAction(); + final int actionMasked = action & MotionEvent.ACTION_MASK; + if (actionMasked == MotionEvent.ACTION_DOWN) { + cancelAndClearTouchTargets(ev); + resetTouchState(); + } + + 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); + } else { + intercepted = false; + } + } else { + intercepted = true; + } + // 不拦截的情况 + if (actionMasked == MotionEvent.ACTION_DOWN + || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) + || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { + final int actionIndex = ev.getActionIndex(); + final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex) + : TouchTarget.ALL_POINTER_IDS; + final int childrenCount = mChildrenCount; + if (newTouchTarget == null && childrenCount != 0) { + final float x = ev.getX(actionIndex); + final float y = ev.getY(actionIndex); + final View[] children = mChildren; + for (int i = childrenCount - 1; i >= 0; i--) { + if (!child.canReceivePointerEvents() + || !isTransformedTouchPointInView(x, y, child, null)) { + continue; + newTouchTarget = getTouchTarget(child); + if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { + break; + } + } + } + } + } + } +} +``` + +如果 ViewGroup 允许拦截,就调用其 onInterceptTouchEvent 来判断是否要真正执行拦截了,这样做了是方便扩展。如果不拦截,就从后遍历子 View 处理。它有两个函数可以过滤子 View,一个是判断这个子 View 能否接收 Pointer Events 事件,另一个是判断落点有没有落在子 View 范围内。如果都满足,则调用其 dispatchTouchEvent 处理。如果该子 View 是一个 ViewGroup 就继续调用其 dispatchTouchEvent,否则就是 View 的 dispatchTouchEvent。如此循环往复,直到事件真正被处理。 \ No newline at end of file