UI事件分发机制(上层)

2022-04-03  本文已影响0人  天上飘的是浮云

之前跟踪了下,手指点击屏幕。点击事件从底层传到App的Activty的过程。今天,来跟踪和理解下Android上层的事件分发机制和策略。

一、事件的L型链和U型链

L型链:消费了事件
L型链
U型链:没有消费事件
U型链

二、设计事件分发考虑的点:

三、ViewGroup的dispatchTouchEvent方法

在ViewGroup中主要是onInterceptTouchEvent和dispatchTouchEvent起作用。

onInterceptTouchEvent主要是拦截事件
dispatchTouchEvent主要分发事件

public boolean dispatchTouchEvent(MotionEvent ev) {
    ...
    boolean handled = false;
    if (onFilterTouchEventForSecurity(ev)) {
        ...
        // Check for interception.
        final boolean intercepted;
        if (actionMasked == MotionEvent.ACTION_DOWN
                || mFirstTouchTarget != null) {
2609行                   intercepted = onInterceptTouchEvent(ev);
        ...
2634行         if (!canceled && !intercepted) {

            if (actionMasked == MotionEvent.ACTION_DOWN
                    || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
                    || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
                ...
                final int childrenCount = mChildrenCount;
                if (newTouchTarget == null && childrenCount != 0) {
                    ...
                    final View[] children = mChildren;
                    //1. 从上到下,倒序遍历,也就是说最上层优先的到点击事件
                    for (int i = childrenCount - 1; i >= 0; i--) {
                        ...
                        //2. 判断点击事件的Point是否在子View的区域范围内
                        // (其实就是看point是否在left/right/top/bottom范围内);
                        if (!child.canReceivePointerEvents()
                                || !isTransformedTouchPointInView(x, y, child, null)) {
                            ev.setTargetAccessibilityFocus(false);
                            continue;
                        }
                        ...
                        //找到子view能接收到Down事件后,调用dispatchTransformedTouchEvent方法
                        // 看子View是否处理事件,如果处理,则将子View添加到TouchTarget里。
                        // 并赋给mFirstTouchTarget。以便下次Move或Up事件时,
                        // 不需要再次遍历寻找子View。
                        if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                            ...
                            mLastTouchDownX = ev.getX();
                            mLastTouchDownY = ev.getY();
                            newTouchTarget = addTouchTarget(child, idBitsToAssign);
                            alreadyDispatchedToNewTouchTarget = true;
                            break;
                        }
                        ...
                }
                ...
            }
        }

        // Dispatch to touch targets.
2739行      if (mFirstTouchTarget == null) {
            // 被拦截或者没有子View处理通过dispatchTransformedTouchEvent
            // 交给自己onTouchEvent处理
            handled = dispatchTransformedTouchEvent(ev, canceled, null,
                    TouchTarget.ALL_POINTER_IDS);
        } else {
            ...
            TouchTarget target = mFirstTouchTarget;
            while (target != null) {
                //move、up事件直接分发,不在寻找
                    if (dispatchTransformedTouchEvent(ev, cancelChild,
                            target.child, target.pointerIdBits)) {
                        handled = true;
                    }
                }
            }
        }
    ...
    return handled;
}
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
            View child, int desiredPointerIdBits) {
...
       if (child == null) {
            handled = super.dispatchTouchEvent(transformedEvent);
        } else {
            final float offsetX = mScrollX - child.mLeft;
            final float offsetY = mScrollY - child.mTop;
            transformedEvent.offsetLocation(offsetX, offsetY);
            if (! child.hasIdentityMatrix()) {
                transformedEvent.transform(child.getInverseMatrix());
            }

            handled = child.dispatchTouchEvent(transformedEvent);
        }
...
}
    private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
        final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
        target.next = mFirstTouchTarget;
        mFirstTouchTarget = target;
        return target;
    }

dispatchTouchEvent中有几个关键点:

四、View的dispatchTouchEvent和onTouchEvent方法

View中的dispatchTouchEvent主要是分发给自己来处理事件。

13424行 if (li != null && li.mOnTouchListener != null
            && (mViewFlags & ENABLED_MASK) == ENABLED
            && li.mOnTouchListener.onTouch(this, event)) {
            result = true;
       }

13430行    if (!result && onTouchEvent(event)) {
                result = true;
            }
上一篇 下一篇

猜你喜欢

热点阅读