美文网首页
ViewGroup的事件分发源码分析

ViewGroup的事件分发源码分析

作者: Utte | 来源:发表于2018-08-04 10:52 被阅读52次

    ViewGroup # dispatchTouchEvent

    @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            // 如果检查对象不空就检查事件,在View中也有这一步,但是传入的嵌套级别为0。
            // 注释中有说如果事件已经被嵌套级别较高的View检查过了就不会再检查一遍了。
            // 所以这里对事件已经进行过1等级的处理了,分发给下级View时就不会重新检查了。
            if (mInputEventConsistencyVerifier != null) {
                mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
            }
    
            // If the event targets the accessibility focused view and this is it, start
            // normal event dispatch. Maybe a descendant is what will handle the click.
            // 如果事件目标是焦点View,并且这个View就处于焦点或是焦点View的嵌套父View
            if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
                // 设置不需要判断,继续正常分发工作,以后就不需要重复判断了。
                ev.setTargetAccessibilityFocus(false);
            }
    
            boolean handled = false;
            // 如果设置了窗口遮挡时过滤,并且确实有窗口遮挡,就过滤。
            // 返回false表示过滤,这个过滤是在构造器通过判断style来设置的。
            // 如果不过滤,就进入下面的操作。
            if (onFilterTouchEventForSecurity(ev)) {
                final int action = ev.getAction();
                final int actionMasked = action & MotionEvent.ACTION_MASK;
    
                // Handle an initial down.
                // 如果是ACTION_DOWN事件,说明是新一事件序列的开始。
                // 进行一些初始化工作,清理之前的状态。
                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.
                    // private void cancelAndClearTouchTargets(MotionEvent event) {
                    //    // 如果上个事件序列中消耗事件的View的引用还没来得及回收
                    //    if (mFirstTouchTarget != null) {
                    //        boolean syntheticEvent = false;
                    //        // 如果事件为空,就创造一个ACTION_CANCEL事件
                    //        // 从disptachTouchEvent()中调用的不会进入这个方法块,因为已经判断了为ACTION_DOWN
                    //        if (event == null) {
                    //            final long now = SystemClock.uptimeMillis();
                    //            event = MotionEvent.obtain(now, now,
                    //                    MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
                    //            event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
                    //            syntheticEvent = true;
                    //        }
                    //        for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
                    //            // 如果参数View设置了PFLAG_CANCEL_NEXT_UP_EVENT标识位,就取消
                    //            // private static boolean resetCancelNextUpFlag(@NonNull View view) {
                    //            //     if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) {
                    //            //         view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
                    //            //         return true;
                    //            //     }
                    //            //     return false;
                    //            // }
                    //            resetCancelNextUpFlag(target.child);
                    //            // 这里主要是想让所有链上的所有View都传递一个ACTION_CANCEL
                    //            // private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
                    //            //         View child, int desiredPointerIdBits) {
                    //            //     final boolean handled;
                    //            //     final int oldAction = event.getAction();
                    //            //     // 需要取消或是事件类型为ACTION_CANCEL
                    //            //     if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
                    //            //         // 传参需要取消,不管event是什么类型,都先设置一个ACTION_CANCEL
                    //            //         event.setAction(MotionEvent.ACTION_CANCEL);
                    //            //         // 如果没有子View了,就交给View来处理
                    //            //         if (child == null) {
                    //            //             handled = super.dispatchTouchEvent(event);
                    //            //         } else {
                    //            //             // 如果有就传递给子View继续分发
                    //            //             handled = child.dispatchTouchEvent(event);
                    //            //         }
                    //            //         // 再设置回原来的样子
                    //            //         event.setAction(oldAction);
                    //            //         return handled;
                    //            //     }
                    //            //     // ......
                    //            // }
                    //            dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
                    //        }
                    //        // private void clearTouchTargets() {
                    //        //     TouchTarget target = mFirstTouchTarget;
                    //        //     if (target != null) {
                    //        //         // 回收链上的每一个TouchTarget
                    //        //         do {
                    //        //             TouchTarget next = target.next;
                    //        //             target.recycle();
                    //        //             target = next;
                    //        //         } while (target != null);
                    //        //         mFirstTouchTarget = null;
                    //        //     }
                    //        // }
                    //        clearTouchTargets();
                    //        // 如果事件为空就回收事件
                    //        if (syntheticEvent) {
                    //            event.recycle();
                    //        }
                    //    }
                    //}
                    cancelAndClearTouchTargets(ev);
                    // private void resetTouchState() {
                    //     回收TouchTarget
                    //     clearTouchTargets();
                    //     撤销PFLAG_CANCEL_NEXT_UP_EVENT
                    //     resetCancelNextUpFlag(this);
                    //     撤销FLAG_DISALOW_INTERCEPT
                    //     所以这个不允许拦截的标志位对ACTION_DOWN事件无效
                    //     mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
                    //     mNestedScrollAxes = SCROLL_AXIS_NONE;
                    // }
                    resetTouchState();
                }
    
                // Check for interception.
                // 检查是否拦截
                final boolean intercepted;
                // 如果是ACTION_DOWN或者事件序列的前几个事件已经有子View消耗了
                if (actionMasked == MotionEvent.ACTION_DOWN
                        || mFirstTouchTarget != null) {
                    final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                    // 没有设置不允许拦截才能去判断是否拦截
                    if (!disallowIntercept) {
                        // 调用onInterceptTouchEvent判断是否需要拦截
                        // 默认返回false,不拦截
                        intercepted = onInterceptTouchEvent(ev);
                        // 防止操作中将event的类型改变了
                        ev.setAction(action); // restore action in case it was changed
                    } else {
                        // 如果设置了,就不拦截
                        intercepted = false;
                    }
                } else {
                    // 没有消耗而且也不是ACTION_DOWN事件,就拦截。
                    // 会有两种情况,
                    // 一种是一开始该ViewGroup就拦截了ACTION_DOWN事件
                    // 或者子View没有消耗前几个事件,它们对于之后的事件也不感兴趣,所以拦截
                    // There are no touch targets and this action is not an initial down
                    // so this view group continues to intercept touches.
                    intercepted = true;
                }
    
                // If intercepted, start normal event dispatch. Also if there is already
                // a view that is handling the gesture, do normal event dispatch.
                // 如果拦截或这已经有View拦截了事件,就开始正常的分发工作
                if (intercepted || mFirstTouchTarget != null) {
                    ev.setTargetAccessibilityFocus(false);
                }
    
                // Check for cancelation.
                // 如果设置了FLAG_CANCEL_NEXT_UP_EVENT就取消这个设置
                // 或者该事件是cancel事件
                final boolean canceled = resetCancelNextUpFlag(this)
                        || actionMasked == MotionEvent.ACTION_CANCEL;
    
                // Update list of touch targets for pointer down, if needed.
                // 是否拆分事件,默认可拆分
                // 注释说在必要的情况下,可以将一个事件分解传递给多个子View
                final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
                TouchTarget newTouchTarget = null;
                boolean alreadyDispatchedToNewTouchTarget = false;
                // 如果事件没有取消且不拦截
                if (!canceled && !intercepted) {
                    
                    
                    
                    
                    // ......
                
                    
                    
                    
                    
                }
    
                // Dispatch to touch targets.
                // 如果事件序列中还没有分发消耗的事件对象
                if (mFirstTouchTarget == null) {
                    // No touch targets so treat this as an ordinary view.
                    // 尝试自己消耗事件
                    handled = dispatchTransformedTouchEvent(ev, canceled, null,
                            TouchTarget.ALL_POINTER_IDS);
                } else {
                    // Dispatch to touch targets, excluding the new touch target if we already
                    // dispatched to it.  Cancel touch targets if necessary.
                    TouchTarget predecessor = null;
                    TouchTarget target = mFirstTouchTarget;
                    while (target != null) {
                        final TouchTarget next = target.next;
                        // 遍历到消耗事件的子View了,置handled为true
                        if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
                            handled = true;
                        } else {
                            // 如果设置了PFLAG_CANCEL_NEXT_UP_EVENT就取消  或  需要拦截 返回true
                            final boolean cancelChild = resetCancelNextUpFlag(target.child)
                                    || intercepted;
                            // 如果cancelChild为true,就让该child分发一个cancel事件
                            // 如果cancelChild为false,就让该child分发该事件
                            if (dispatchTransformedTouchEvent(ev, cancelChild,
                                    target.child, target.pointerIdBits)) {
                                handled = true;
                            }
                            if (cancelChild) {
                                // 如果是取消就清除回收这个结点
                                if (predecessor == null) {
                                    mFirstTouchTarget = next;
                                } else {
                                    predecessor.next = next;
                                }
                                // 回收
                                target.recycle();
                                // 向后移
                                target = next;
                                continue;
                            }
                        }
                        // 向后移动
                        predecessor = target;
                        target = next;
                    }
                }
    
                // Update list of touch targets for pointer up or cancel, if needed.
                if (canceled
                        || actionMasked == MotionEvent.ACTION_UP
                        || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
                    // 如果是取消或up事件或鼠标移动事件,就清空所有状态
                    resetTouchState();
                } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
                    // 当有手指抬起时,清空这个手指之前触碰点的所有信息
                    final int actionIndex = ev.getActionIndex();
                    final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
                    // private void removePointersFromTouchTargets(int pointerIdBits) {
                    //    TouchTarget predecessor = null;
                    //    TouchTarget target = mFirstTouchTarget;
                    //    while (target != null) {
                    //        final TouchTarget next = target.next;
                    //        if ((target.pointerIdBits & pointerIdBits) != 0) {
                    //            target.pointerIdBits &= ~pointerIdBits;
                    //            // 如果除了需要删除的值之外就没有别的了,就将这个结点删除并回收
                    //            if (target.pointerIdBits == 0) {
                    //                if (predecessor == null) {
                    //                    mFirstTouchTarget = next;
                    //                } else {
                    //                    predecessor.next = next;
                    //                }
                    //                target.recycle();
                    //                target = next;
                    //                continue;
                    //            }
                    //        }
                    //        predecessor = target;
                    //        target = next;
                    //    }
                    //}
                    removePointersFromTouchTargets(idBitsToRemove);
                }
            }
            // 发起检查
            if (!handled && mInputEventConsistencyVerifier != null) {
                mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
            }
            return handled;
        }
    

    非取消事件且不拦截的分发消耗过程

    if (!canceled && !intercepted) {
        // If the event is targeting accessiiblity focus we give it to the
        // view that has accessibility focus and if it does not handle it
        // we clear the flag and dispatch the event to all children as usual.
        // We are looking up the accessibility focused host to avoid keeping
        // state since these events are very rare.
        // 如果该View设置了FLAG_TARGET_ACCESSIBILITY_FOCUS
        // 就找到下一层正真处焦点的View
        // private View findChildWithAccessibilityFocus() {
        //    ViewRootImpl viewRoot = getViewRootImpl();
        //    if (viewRoot == null) {
        //        return null;
        //    }
        //    View current = viewRoot.getAccessibilityFocusedHost();
        //    if (current == null) {
        //        return null;
        //    }
        //    ViewParent parent = current.getParent();
        //    // 一层一层向上找
        //    // 直到找到一个View为该ViewGroup的child并且还嵌套着焦点View
        //    while (parent instanceof View) {
        //        if (parent == this) {
        //            return current;
        //        }
        //        current = (View) parent;
        //        parent = current.getParent();
        //    }
        //    // 如果没有找到,说明该ViewGroup没有嵌套焦点View
        //    return null;
        //}
        View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
                ? findChildWithAccessibilityFocus() : null;
        // 如果是ACTION_DOWN
        // 或可分离且非第一个手指按下的情况,比如第一个手指按下并没有松开,此时又一只手指按下
        // 或者是鼠标移动且并未点击,4.0后会监听鼠标移动
        if (actionMasked == MotionEvent.ACTION_DOWN
                || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
                || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
            // 多点触控时,这个值会往上加
            final int actionIndex = ev.getActionIndex(); // always 0 for down
            // 如果可分离就通过索引获取的值左移一位
            // 否则取常量 -1
            final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
                    : TouchTarget.ALL_POINTER_IDS;
            // Clean up earlier touch targets for this pointer id in case they
            // have become out of sync.
            // 清除这个id早前的作用
            removePointersFromTouchTargets(idBitsToAssign);
            final int childrenCount = mChildrenCount;
            if (newTouchTarget == null && childrenCount != 0) {
                final float x = ev.getX(actionIndex);
                final float y = ev.getY(actionIndex);
                // Find a child that can receive the event.
                // Scan children from front to back.
                // public ArrayList<View> buildTouchDispatchChildList() {
                //     return buildOrderedChildList();
                // }
                // ArrayList<View> buildOrderedChildList() {
                //     final int childrenCount = mChildrenCount;
                //     // 如果子View数小于等于1
                //     // 或者遍历子view不存在子getZ()不为0的view,也就是没有都没有高度时
                //     // z属性用于描述视图距离它父视图的高度
                //     if (childrenCount <= 1 || !hasChildWithZ()) return null;
                //     if (mPreSortedChildren == null) {
                //         mPreSortedChildren = new ArrayList<>(childrenCount);
                //     } else {
                //         // callers should clear, so clear shouldn't be necessary, but for safety...
                //         mPreSortedChildren.clear();
                //         // 重新分配日大小
                //         mPreSortedChildren.ensureCapacity(childrenCount);
                //     }
                //     final boolean customOrder = isChildrenDrawingOrderEnabled();
                //     // 开始遍历子View
                //     for (int i = 0; i < childrenCount; i++) {
                //         // add next child (in child order) to end of list
                //         // 是否设置有FLAG_USE_CHILD_DRAWING_ORDER
                //         // 如果设置了,绘制的方法就会通过调用getChildDrawingOrder()来决定绘制子View的顺序。
                //         // private int getAndVerifyPreorderedIndex(int childrenCount, int i, boolean customOrder) {
                //         //     final int childIndex;
                //         //     // 如果需要根据getChildDrawingOrder()排序子view的绘制顺序,就需要获得绘制顺序
                //         //     if (customOrder) {
                //         //         // 得到第i个View的绘制顺序,如果没有重写getChildDrawingOrder(),就会直接返回i
                //         //         // protected int getChildDrawingOrder(int childCount, int i) {
                //         //         //     return i;
                //         //         // }
                //         //         final int childIndex1 = getChildDrawingOrder(childrenCount, i);
                //         //         // 如果大于总数了,就抛异常
                //         //         if (childIndex1 >= childrenCount) {
                //         //             throw new IndexOutOfBoundsException("getChildDrawingOrder() "
                //         //                     + "returned invalid index " + childIndex1
                //         //                     + " (child count is " + childrenCount + ")");
                //         //         }
                //        //         childIndex = childIndex1;
                //         //     } else {
                //         //         // 否则直接返回遍历的下标
                //         //         childIndex = i;
                //         //     }
                //         //     return childIndex;
                //         // }
                //         final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
                //         // 获得这个View
                //         final View nextChild = mChildren[childIndex];
                //         final float currentZ = nextChild.getZ();
                //         // insert ahead of any Views with greater Z
                //         int insertIndex = i;
                //         // 向数组前面遍历查找是否有深度大于当前子View的
                //         while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) {
                //             insertIndex--;
                //         }
                //         // 将当前子View插入到这个位置,使集合按getZ()从小到大排序
                //         mPreSortedChildren.add(insertIndex, nextChild);
                //     }
                //     // 将排序好的集合返回
                //     return mPreSortedChildren;
                // }
                final ArrayList<View> preorderedList = buildTouchDispatchChildList();
                // true 完全根据排序方法的自定义实现,getZ()都不考虑
                final boolean customOrder = preorderedList == null
                        && isChildrenDrawingOrderEnabled();
                final View[] children = mChildren;
                // 从后往前
                for (int i = childrenCount - 1; i >= 0; i--) {
                    // 获取设置了顺序绘制后对应第i个绘制的view的下标
                    final int childIndex = getAndVerifyPreorderedIndex(
                            childrenCount, i, customOrder);
                    // preorderedList不空就从它里面取出第childIndex个View
                    // 空的话从children中取
                    // 变量:几个child 是否设置了z 是否设置绘制顺序排序
                    //   0   小于两个    都没设置        没有
                    // 完全默认顺序
                    // 0 0 0   childIndex默认     children的第i个
                    // 0 1 0   childIndex默认     children的第i个
                    // 0 1 0   childIndex默认     children的第i个
                    // 1 0 0   childIndex默认     children的第i个
                    // 完全绘制排序
                    // 0 0 1   childIndex有顺序   children的第i对应的顺序个
                    // 0 1 1   childIndex有顺序   children的第childIndex个
                    // 1 0 1   childIndex有顺序   children的第childIndex个
                    // 第一排序为getZ()的升序 第二排序会绘制顺序
                    // 1 1 0   childIndex默认     preorderedList的第i个
                    // 1 1 1   childIndex默认     preorderedList的第i个
                    final View child = getAndVerifyPreorderedView(
                            preorderedList, children, childIndex);
                    // If there is a view that has accessibility focus we want it
                    // to get the event first and if not handled we will perform a
                    // normal dispatch. We may do a double iteration but this is
                    // safer given the timeframe.
                    // 该viewgroup设置事件了指向焦点View并且焦点View在前面已经找到了
                    if (childWithAccessibilityFocus != null) {
                        // 判断遍历的此View是否是焦点View,如果不是就直接下一遍循环
                        if (childWithAccessibilityFocus != child) {
                            continue;
                        }
                        // 如果是的话就将找到的焦点view置空
                        // i回到到数第一个下标
                        // 这样做的目的是先让该焦点view尝试进行下面的普通分发操作
                        // 如果成功了,会在下面跳出循环。
                        // 如果不成功,就将记录的焦点view置空,
                        // 从最后一个开始重新遍历,不再进入这个判断。
                        childWithAccessibilityFocus = null;
                        i = childrenCount - 1;
                    }
                    // private static boolean canViewReceivePointerEvents(@NonNull View child) {
                    //     // 可见或者存在动画
                    //     return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
                    //             || child.getAnimation() != null;
                    // }
                    // isTransformedTouchPointInView()用来盘那段事件是否在view的范围内
                    // protected boolean isTransformedTouchPointInView(float x, float y, View child,
                    //         PointF outLocalPoint) {
                    //     final float[] point = getTempPoint();
                    //     point[0] = x;
                    //     point[1] = y;
                    //     // 把原来相对于该ViewGroup的坐标转换为相对于正在遍历的这个View的相对坐标
                    //     // public void transformPointToViewLocal(float[] point, View child) {
                    //     //     point[0] += mScrollX - child.mLeft;
                    //     //     point[1] += mScrollY - child.mTop;
                    //     //     if (!child.hasIdentityMatrix()) {
                    //     //         child.getInverseMatrix().mapPoints(point);
                    //     //     }
                    //     // }
                    //     transformPointToViewLocal(point, child);
                    //     // /*package*/ final boolean pointInView(float localX, float localY) {
                    //     //     return pointInView(localX, localY, 0);
                    //     // }
                    //     // public boolean pointInView(float localX, float localY, float slop) {
                    //     //     return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) &&
                    //     //             localY < ((mBottom - mTop) + slop);
                    //     // }
                    //     // 判断是否在view的范围内
                    //     final boolean isInView = child.pointInView(point[0], point[1]);
                    //     // 将转换后的坐标设置给outLocalPoint
                    //     if (isInView && outLocalPoint != null) {
                    //         outLocalPoint.set(point[0], point[1]);
                    //     }
                    //     // 返回是否在范围内
                    //     return isInView;
                    // }
                    // 如果不可见并且没有动画 或者 事件不在该View范围内
                    if (!canViewReceivePointerEvents(child)
                            || !isTransformedTouchPointInView(x, y, child, null)) {
                        // 设置false,直接跳出进入下一次循环
                        ev.setTargetAccessibilityFocus(false);
                        continue;
                    }
                    // 找到child是正在遍历的view的Touch Target
                    newTouchTarget = getTouchTarget(child);
                    // 如果存在,说明这个view之前处理过事件,再给它这个事件并跳出循环。
                    if (newTouchTarget != null) {
                        // Child is already receiving touch within its bounds.
                        // Give it the new pointer in addition to the ones it is handling.
                        newTouchTarget.pointerIdBits |= idBitsToAssign;
                        break;
                    }
                    // 取消该view的PFLAG_CANCEL_NEXT_UP_EVENT
                    resetCancelNextUpFlag(child);
                    // 将事件传递给child看是否能分发消耗成功,如果成功就进方法块
                    if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                        // Child wants to receive touch within its bounds.
                        mLastTouchDownTime = ev.getDownTime();
                        if (preorderedList != null) {
                            // childIndex points into presorted list, find original index
                            for (int j = 0; j < childrenCount; j++) {
                                if (children[childIndex] == mChildren[j]) {
                                    // 找到该view的原始下标
                                    mLastTouchDownIndex = j;
                                    break;
                                }
                            }
                        } else {
                            // 如果集合为空,也就说明child是根据原始下标取出的,直接赋值
                            mLastTouchDownIndex = childIndex;
                        }
                        mLastTouchDownX = ev.getX();
                        mLastTouchDownY = ev.getY();
                        // 上面已经判断了Touch Target存在的情况
                        // 这里一定不存在,新创建一个对象并加入链表
                        // private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
                        //     final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
                        //     target.next = mFirstTouchTarget;
                        //     mFirstTouchTarget = target;
                        //     return target;
                        // }
                        // 头插,现在mFirstTouchTarget就指向这个view的touch target了
                        newTouchTarget = addTouchTarget(child, idBitsToAssign);
                        // 置为true表示已经分发给新目标了
                        alreadyDispatchedToNewTouchTarget = true;
                        // 跳出遍历子View的循环
                        break;
                    }
                    // The accessibility focus didn't handle the event, so clear
                    // the flag and do a normal dispatch to all children.
                    // 焦点View没有成功处理事件所以将flag置为false,以后就普通的去遍历分发了
                    ev.setTargetAccessibilityFocus(false);
                }
                // 清空排序集合
                if (preorderedList != null) preorderedList.clear();
            }
            // 只有当上面的if判断没有进入才会出现newTouchTarget为空的现象
            // 就说明该viewgroup的子view数量为0
            // 没有子view并且之前消耗过事件
            if (newTouchTarget == null && mFirstTouchTarget != null) {
                // Did not find a child to receive the event.
                // Assign the pointer to the least recently added target.
                newTouchTarget = mFirstTouchTarget;
                // 找到消耗链表的最后一个元素,也就是第一个被添加的元素,down事件消耗的view
                while (newTouchTarget.next != null) {
                    newTouchTarget = newTouchTarget.next;
                }
                // 给这个目标加上这个事件的id
                newTouchTarget.pointerIdBits |= idBitsToAssign;
            }
        }
    }
    

    dispatchTouchEvent()框图

    分发消耗框图

    排序子View数组框图

    相关文章

      网友评论

          本文标题:ViewGroup的事件分发源码分析

          本文链接:https://www.haomeiwen.com/subject/hzbqvftx.html