捋不清的源码---Android事件分发

516 阅读5分钟

ViewGroup的dispatchTouchEvent相关源码

boolean handled = false;
...
if (actionMasked == MotionEvent.ACTION_DOWN) {
    //清除所有的触摸链touch targets,mFirstTouchTarget为null
    //重置touch状态标识,所以说明requestDisallowInterceptTouchEvent方法对于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 {
    //不是DOWN事件并且mFirstTouchTarget为null,说明拦截Touch事件
    intercepted = true;
}

mFirstTouchTarget不为null表示没有拦截了事件并且子View消费了该事件。

mFirstTouchTarget为null表示拦截了事件或者没有拦截但是子View没有消费该事件。

    boolean alreadyDispatchedToNewTouchTarget = false;
    if (!canceled && !intercepted) {
   	    ....
        if (actionMasked == MotionEvent.ACTION_DOWN
            || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
            || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
       	    ...
            if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                ... 
                //方法内把消费了事件的View添加到了touch targets中,
                //即mFirstTouchTarget此时不为null。可知,如果dispatchTransformedTouchEvent为false(不消费),
                //那么 mFirstTouchTarget就为null
                newTouchTarget = addTouchTarget(child, idBitsToAssign);
                //事件被消费,设置为true,下面判断会使用到
                alreadyDispatchedToNewTouchTarget = true;
                break;
            }
            ...
        }
        ...
    }

        if (newTouchTarget == null && mFirstTouchTarget != null) {
            newTouchTarget = mFirstTouchTarget;
            while (newTouchTarget.next != null) {
                newTouchTarget = newTouchTarget.next;
            }
            newTouchTarget.pointerIdBits |= idBitsToAssign;
        }
    }
}

//事件分发给子View
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
        View child, int desiredPointerIdBits) {
    ...
    if (child == null) {
    	//直接到View的dispatchTouchEvent处理事件
        handled = super.dispatchTouchEvent(event);
    } else {
    	...
        handled = child.dispatchTouchEvent(event);
    }
}
    if (mFirstTouchTarget == null) {
        //此时事件被拦截了或者事件没有子View消费,自己处理事件
        handled = dispatchTransformedTouchEvent(ev, canceled, null,
                        TouchTarget.ALL_POINTER_IDS);
    } else {
        TouchTarget predecessor = null;
        TouchTarget target = mFirstTouchTarget;
        while (target != null) {
            final TouchTarget next = target.next;
            //只有DOWN事件被消费了alreadyDispatchedToNewTouchTarget设置为true才会到这里
            //不处理直接返回true
            if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
                handled = true;
            } else {
                //处理除了DOWN事件以外的事件分发
                final boolean cancelChild = resetCancelNextUpFlag(target.child)
                                || intercepted;
                if (dispatchTransformedTouchEvent(ev, cancelChild,
                                target.child, target.pointerIdBits)) {
                    handled = true;
                }
                //mFirstTouchTarget最终会变为null
                if (cancelChild) {
                    if (predecessor == null) {
                        mFirstTouchTarget = next;
                    } else {
                        predecessor.next = next;
                    }
                    target.recycle();
                    target = next;
                    continue;
                }
            }
            predecessor = target;
            target = next;
        }
    }   

测试

布局为ViewGroupA里面添加ViewGroupB里面添加View

View的clickable设置为true。

E/Test-Activity:    dispatchTouchEvent:ACTION_DOWN
E/Test-ViewGroup—A: dispatchTouchEvent:ACTION_DOWN
E/Test-ViewGroup—A: onInterceptTouchEvent:ACTION_DOWN
E/Test-ViewGroup—B: dispatchTouchEvent:ACTION_DOWN
E/Test-ViewGroup—B: onInterceptTouchEvent:ACTION_DOWN
E/Test-View: 	    dispatchTouchEvent:ACTION_DOWN
E/Test-View: 	    onTouchEvent:ACTION_DOWN

E/Test-Activity:    dispatchTouchEvent:ACTION_MOVE
E/Test-ViewGroup—A: dispatchTouchEvent:ACTION_MOVE
E/Test-ViewGroup—A: onInterceptTouchEvent:ACTION_MOVE
E/Test-ViewGroup—B: dispatchTouchEvent:ACTION_MOVE
E/Test-ViewGroup—B: onInterceptTouchEvent:ACTION_MOVE
E/Test-View: 	    dispatchTouchEvent:ACTION_MOVE
E/Test-View: 	    onTouchEvent:ACTION_MOVE

E/Test-Activity:    dispatchTouchEvent:ACTION_UP
E/Test-ViewGroup—A: dispatchTouchEvent:ACTION_UP
E/Test-ViewGroup—A: onInterceptTouchEvent:ACTION_UP
E/Test-ViewGroup—B: dispatchTouchEvent:ACTION_UP
E/Test-ViewGroup—B: onInterceptTouchEvent:ACTION_UP
E/Test-View: 	    dispatchTouchEvent:ACTION_UP
E/Test-View: 	    onTouchEvent:ACTION_UP

只要子View是可点击的就会消费事件,所以子View消费DOWN事件,两个ViewGroup的mFirstTouchTarget都不为null,所以此时的MOVE和UP事件正常经过dispatchTouchEvent和onInterceptTouchEvent,通过dispatchTransformedTouchEvent分发到View处理事件。

View不设置clickable

E/Test-Activity:    dispatchTouchEvent:ACTION_DOWN
E/Test-ViewGroup—A: dispatchTouchEvent:ACTION_DOWN
E/Test-ViewGroup—A: onInterceptTouchEvent:ACTION_DOWN
E/Test-ViewGroup—B: dispatchTouchEvent:ACTION_DOWN
E/Test-ViewGroup—B: onInterceptTouchEvent:ACTION_DOWN
E/Test-View: 	    dispatchTouchEvent:ACTION_DOWN
E/Test-View: 	    onTouchEvent:ACTION_DOWN
E/Test-ViewGroup—B: onTouchEvent:ACTION_DOWN
E/Test-ViewGroup—A: onTouchEvent:ACTION_DOWN
E/Test-Activity:    onTouchEvent:ACTION_DOWN

E/Test-Activity:    dispatchTouchEvent:ACTION_MOVE
E/Test-Activity:    onTouchEvent:ACTION_MOVE

E/Test-Activity:    dispatchTouchEvent:ACTION_UP
E/Test-Activity:    onTouchEvent:ACTION_UP

DOWN事件分发到View,但是没有View去消费该事件,则View的onTouchEvent返回false,B的mFirstTouchTarget为null,B自身处理事件onTouchEvent返回false,A同样处理返回false一直到Activity,getWindow().superDispatchTouchEvent(ev)返回false,调用自己的onTouchEvent处理事件。由于现在的mFirstTouchTarget都为null,所以MOVE和UP事件不会被分发到子View处理。

View的clickable设置为true,B的dispatchTouchEvent的Down事件return true

E/Test-Activity:    dispatchTouchEvent:ACTION_DOWN
E/Test-ViewGroup—A: dispatchTouchEvent:ACTION_DOWN
E/Test-ViewGroup—A: onInterceptTouchEvent:ACTION_DOWN
E/Test-ViewGroup—B: dispatchTouchEvent:ACTION_DOWN

E/Test-Activity:    dispatchTouchEvent:ACTION_MOVE
E/Test-ViewGroup—A: dispatchTouchEvent:ACTION_MOVE
E/Test-ViewGroup—A: onInterceptTouchEvent:ACTION_MOVE
E/Test-ViewGroup—B: dispatchTouchEvent:ACTION_MOVE
E/Test-ViewGroup—B: onTouchEvent:ACTION_MOVE
E/Test-Activity:    onTouchEvent:ACTION_MOVE

E/Test-Activity:    dispatchTouchEvent:ACTION_UP
E/Test-ViewGroup—A: dispatchTouchEvent:ACTION_UP
E/Test-ViewGroup—A: onInterceptTouchEvent:ACTION_UP
E/Test-ViewGroup—B: dispatchTouchEvent:ACTION_UP
E/Test-ViewGroup—B: onTouchEvent:ACTION_UP
E/Test-Activity:    onTouchEvent:ACTION_UP

A正常分发到B,但是B的DOWN事件直接返回了true,所以B的mFirstTouchTarget为null,A的mFirstTouchTarget不为null,此时alreadyDispatchedToNewTouchTarget为true,DOWN事件不会继续分发下去直接设置handled为true,那么Activity由于getWindow().superDispatchTouchEven为true也不会调用onTouchEvent。MOVE和UP事件到来的时候,由于B的mFirstTouchTarget为null,在开始判断里面不会走onInterceptTouchEvent而是直接设置intercept为true,然后走自身的onTouchEvent方法返回false。A的mFirstTouchTarget不为null,dispatchTransformedTouchEvent为false,handled默认为false,所以到Activity的时候,会调用onTouchEvent。

B的onInterceptTouchEvent的DONW事件return true

E/Test-Activity:    dispatchTouchEvent:ACTION_DOWN
E/Test-ViewGroup—A: dispatchTouchEvent:ACTION_DOWN
E/Test-ViewGroup—A: onInterceptTouchEvent:ACTION_DOWN
E/Test-ViewGroup—B: dispatchTouchEvent:ACTION_DOWN
E/Test-ViewGroup—B: onInterceptTouchEvent:ACTION_DOWN
E/Test-ViewGroup—B: onTouchEvent:ACTION_DOWN
E/Test-ViewGroup—A: onTouchEvent:ACTION_DOWN
E/Test-Activity:    onTouchEvent:ACTION_DOWN

E/Test-Activity:    dispatchTouchEvent:ACTION_MOVE
E/Test-Activity:    onTouchEvent:ACTION_MOVE

E/Test-Activity:    dispatchTouchEvent:ACTION_UP
E/Test-Activity:    onTouchEvent:ACTION_UP

DOWN事件在B中被拦截了,intercept为true,该事件将不会分到到子View,所以B的mFirstTouchTarget为null,调用自己的onTouchEvent返回false,所以A中dispatchTransformedTouchEvent返回为false,此时的mFirstTouchTarget也为null,调用自己的onTouchEvent返回false,Activity调用onTouchEvent。由于此时所有的mFirstTouchTarget都为null,所以MOVE和UP事件都只会在Activity中处理。

B的onInterceptTouchEvent的MOVE事件return true

E/Test-Activity:    dispatchTouchEvent:ACTION_DOWN
E/Test-ViewGroup—A: dispatchTouchEvent:ACTION_DOWN
E/Test-ViewGroup—A: onInterceptTouchEvent:ACTION_DOWN
E/Test-ViewGroup—B: dispatchTouchEvent:ACTION_DOWN
E/Test-ViewGroup—B: onInterceptTouchEvent:ACTION_DOWN
E/Test-View: 	    dispatchTouchEvent:ACTION_DOWN
E/Test-View: 	    onTouchEvent:ACTION_DOWN

E/Test-Activity:    dispatchTouchEvent:ACTION_UP
E/Test-ViewGroup—A: dispatchTouchEvent:ACTION_UP
E/Test-ViewGroup—A: onInterceptTouchEvent:ACTION_UP
E/Test-ViewGroup—B: dispatchTouchEvent:ACTION_UP
E/Test-ViewGroup—B: onInterceptTouchEvent:ACTION_UP
E/Test-View: 	    dispatchTouchEvent:ACTION_UP
E/Test-View: 	    onTouchEvent:ACTION_UP

此时没有MOVE事件,DOWN和UP事件正常分发到View上面消费。

E/Test-Activity:    dispatchTouchEvent:ACTION_DOWN
E/Test-ViewGroup—A: dispatchTouchEvent:ACTION_DOWN
E/Test-ViewGroup—A: onInterceptTouchEvent:ACTION_DOWN
E/Test-ViewGroup—B: dispatchTouchEvent:ACTION_DOWN
E/Test-ViewGroup—B: onInterceptTouchEvent:ACTION_DOWN
E/Test-View: 	    dispatchTouchEvent:ACTION_DOWN
E/Test-View: 	    onTouchEvent:ACTION_DOWN

E/Test-Activity:    dispatchTouchEvent:ACTION_MOVE
E/Test-ViewGroup—A: dispatchTouchEvent:ACTION_MOVE
E/Test-ViewGroup—A: onInterceptTouchEvent:ACTION_MOVE
E/Test-ViewGroup—B: dispatchTouchEvent:ACTION_MOVE
E/Test-ViewGroup—B: onInterceptTouchEvent:ACTION_MOVE

E/Test-Activity:    dispatchTouchEvent:ACTION_MOVE
E/Test-ViewGroup—A: dispatchTouchEvent:ACTION_MOVE
E/Test-ViewGroup—A: onInterceptTouchEvent:ACTION_MOVE
E/Test-ViewGroup—B: dispatchTouchEvent:ACTION_MOVE
E/Test-ViewGroup—B: onTouchEvent:ACTION_MOVE
E/Test-Activity:    onTouchEvent:ACTION_MOVE

E/Test-Activity:    dispatchTouchEvent:ACTION_UP
E/Test-ViewGroup—A: dispatchTouchEvent:ACTION_UP
E/Test-ViewGroup—A: onInterceptTouchEvent:ACTION_UP
E/Test-ViewGroup—B: dispatchTouchEvent:ACTION_UP
E/Test-ViewGroup—B: onTouchEvent:ACTION_UP
E/Test-Activity:    onTouchEvent:ACTION_UP

DOWN事件的时候,A和B的mFirstTouchTarget都不为null,MOVE事件到来的时候,此时intercept为true,则cancelChild为true,B的mFirstTouchTarget会变为null,在接下来的MOVE事件到来的时候,会调用自己的onTouchEvent返回false到A默认handled默认返回false,Activity调用onTouchEvent。