事件分发

来源:互联网 发布:共享无法启用网络发现 编辑:程序博客网 时间:2024/05/18 02:57

如果你抱着批评指正的态度来看的,欢迎之至,希望你能提出我的错误并指正,但是如果你抱着学习的态度来看的,我希望你另找一家,内容写的比较懵懂,个人感觉并不适合学习。

其实不是太敢写,毕竟自己也是懵懂状态,但是学习过程中不写的话总是理解的要差那么一点意思,所以就记录一下自己目前所了解的,等有了更深的了解再来颠覆自己,而且在需要的时候,方便查看找到自己及时需要的。

事件分发总也离不开三个方法:

public boolean dispatchTouchEvent(MotionEvent ev)public boolean onInterceptTouchEvent(MotionEvent ev)public boolean onTouchEvent(MotionEvent ev)

简单的来说就是这三个方法在运转:
然后针对View又分两种:ViewGroup和View
在手指点击之后,经过层层分发最终到顶层ViewGroup

ViewGroup需要在dispatchTouchEvent中判断onInterceptTouchEvent的返回值来判断是否进行拦截,
如果拦截则交给自己的onTouchEvent来处理,如果不拦截则将事件分给给它的子View去分发处理。

ViewGroup的伪代码:

public boolean dispatchTouchEvent(MotionEvent ev) {        boolean consume=false;        if (onInterceptTouchEvent(ev)){            consume=onTouchEvent(ev);        }else {            consume=child.dispatchTouchEvent(ev);        }        return consume;    }

以上伪代码可看出运行流程

public boolean dispatchTouchEvent(MotionEvent ev) {        ...        boolean handled = false;        if (onFilterTouchEventForSecurity(ev)) {            final int action = ev.getAction();            final int actionMasked = action & MotionEvent.ACTION_MASK;            // Handle an initial 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.                cancelAndClearTouchTargets(ev);                //重置标签                resetTouchState();            }            // Check for interception.            final boolean intercepted;            //mFirstTouchTarget在ViewGroup不拦截下发给子View的时候赋值!=null,拦截则=null            if (actionMasked == MotionEvent.ACTION_DOWN                    || mFirstTouchTarget != null) {                    //通过标签位FLAG_DISALLOW_INTERCEPT来判断是否不允许拦截                    //如果是不允许拦截(disallowIntercept=true)则intercepted = false                    //否则获取onInterceptTouchEvent(ev)的值进行设置是否拦截                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.                //后续MOVE、UP...持续拦截                intercepted = true;            }            // If intercepted, start normal event dispatch. Also if there is already            // a view that is handling the gesture, do normal event dispatch.            if (intercepted || mFirstTouchTarget != null) {                ev.setTargetAccessibilityFocus(false);            }            // Check for cancelation.            final boolean canceled = resetCancelNextUpFlag(this)                    || actionMasked == MotionEvent.ACTION_CANCEL;            // Update list of touch targets for pointer down, if needed.            final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;            TouchTarget newTouchTarget = null;            boolean alreadyDispatchedToNewTouchTarget = false;            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 childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()                        ? findChildWithAccessibilityFocus() : null;                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                    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.                    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.                        final ArrayList<View> preorderedList = buildTouchDispatchChildList();                        final boolean customOrder = preorderedList == null                                && isChildrenDrawingOrderEnabled();                        final View[] children = mChildren;                        for (int i = childrenCount - 1; i >= 0; i--) {                            final int childIndex = getAndVerifyPreorderedIndex(                                    childrenCount, i, customOrder);                            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.                            if (childWithAccessibilityFocus != null) {                                if (childWithAccessibilityFocus != child) {                                    continue;                                }                                childWithAccessibilityFocus = null;                                i = childrenCount - 1;                            }                            if (!canViewReceivePointerEvents(child)                                    || !isTransformedTouchPointInView(x, y, child, null)) {                                ev.setTargetAccessibilityFocus(false);                                continue;                            }                            newTouchTarget = getTouchTarget(child);                            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;                            }                            resetCancelNextUpFlag(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]) {                                            mLastTouchDownIndex = j;                                            break;                                        }                                    }                                } else {                                    mLastTouchDownIndex = childIndex;                                }                                mLastTouchDownX = ev.getX();                                mLastTouchDownY = ev.getY();                                newTouchTarget = addTouchTarget(child, idBitsToAssign);                                alreadyDispatchedToNewTouchTarget = true;                                break;                            }                            // The accessibility focus didn't handle the event, so clear                            // the flag and do a normal dispatch to all children.                            ev.setTargetAccessibilityFocus(false);                        }                        if (preorderedList != null) preorderedList.clear();                    }                    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;                        while (newTouchTarget.next != null) {                            newTouchTarget = newTouchTarget.next;                        }                        newTouchTarget.pointerIdBits |= idBitsToAssign;                    }                }            }            // 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;                    if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {                        handled = true;                    } else {                        final boolean cancelChild = resetCancelNextUpFlag(target.child)                                || intercepted;                        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) {                resetTouchState();            } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {                final int actionIndex = ev.getActionIndex();                final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);                removePointersFromTouchTargets(idBitsToRemove);            }        }        if (!handled && mInputEventConsistencyVerifier != null) {            mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);        }        return handled;    }

View需要在dispatchTouchEvent中判断是否设置了OnTouchListener,是否是可用的,然后在onTouch中的返回值,对三者进行判断,如果都为true则直接返回不执行onTouchEvent,否则去onTouchEvent中执行,根据onTouchEvent的返回值来判断dispatchTouchEvent的返回值。

View的截取代码:

boolean result = false;...ListenerInfo li = mListenerInfo;if (li != null && li.mOnTouchListener != null    && (mViewFlags & ENABLED_MASK) == ENABLED    && li.mOnTouchListener.onTouch(this, event)) {    result = true;}if (!result && onTouchEvent(event)) {    result = true;}...return result;

这里差不多就是常用的东西了。

然后,

在onTouchEvent中:

public boolean onTouchEvent(MotionEvent event) {        ...        if (((viewFlags & CLICKABLE) == CLICKABLE ||                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||                (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {            switch (action) {                case MotionEvent.ACTION_UP:                    ...                    performClick();                    ...                    break;                case MotionEvent.ACTION_DOWN:                    ...                    checkForLongClick(0, x, y);                    break;                case MotionEvent.ACTION_CANCEL:                    ...                    break;                case MotionEvent.ACTION_MOVE:                    ...                    break;            }            return true;        }        return false;    }

在上面代码中判断当前View是否处于clickable或longclickable处于true的状态,在触摸下去触发DOWN状态是,进行了LongClickListener的可用检查,在UP状态中判断触发了Click事件。跳出来看只有在这些为可用的状态下(clickable或longclickable处于true的状态)他最终都返回true,反之false。

胡乱总结(都是测试总结):

1、当子View的onTouchEvent返回false时,首先触摸的时候,通过分发到达子View的onTouchEvent(假设),触发的ACTION_DOWN事件,然后返回了false,所以他的dispatchTouchEvent也就返回了false,所以这时候就来判断调用ViewGroup的OnTouchEvent,判断ViewGroup的onTouchEvent的返回值,如果返回false,则接着往上传,true则继续ViewGroup的ACTION_MOVE和ACTION_UP事件的处理,此时已经没有字View什么事了。

2、接上,在ViewGroup的onTouchEvent的ACTION_DOWN中返回false,则事件上传,返回true则整个事件流转,然后则ACTION_MOVE和ACTION_UP中无论返回什么都是正常事件流转,View中同样如此。

3、接上,View中的dispatchTouchEvent同样如此

4、接上,在ViewGroup中dispatchTouchEvent中做同样操作,如果dispatchTouchEvent的ACTION_DOWN返回了false则整个事件结束,事件上传;如果dispatchTouchEvent的ACTION_DOWN返回了true则意味拦截,直接不调用onInterceptTouchEvent,然后是系列的dispatchTouchEvent的ACTION事件和onTouchEvent的ACTION事件;

12-13 16:34:25.423 20187-20187/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-13 16:34:25.451 20187-20187/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_MOVE12-13 16:34:25.451 20187-20187/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_MOVE12-13 16:34:25.452 20187-20187/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_UP12-13 16:34:25.452 20187-20187/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_UP

如果dispatchTouchEvent的ACTION_MOVE返回了true,同上,

12-13 16:32:55.107 20000-20000/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-13 16:32:55.123 20000-20000/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_MOVE12-13 16:32:55.156 20000-20000/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_UP12-13 16:32:55.157 20000-20000/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_UP

如果dispatchTouchEvent的ACTION_UP返回了true,同上(累加的意思,就是所有的ACTION都返回true)

12-13 16:35:13.483 20351-20351/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-13 16:35:13.513 20351-20351/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_MOVE12-13 16:35:13.522 20351-20351/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_UP

则整个都不经过onTouchEvent

都返回false,则事件上传

12-13 16:37:40.473 20577-20577/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-13 16:37:40.473 20577-20577/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_DOWN12-13 16:37:40.473 20577-20577/com.xiey94.scoller E/TAG: View-dispatchTouchEvent-ACTION_DOWN12-13 16:37:40.473 20577-20577/com.xiey94.scoller E/TAG: View-onTouchEvent-ACTION_DOWN12-13 16:37:40.473 20577-20577/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_DOWN

5、ViewGroup的onInterceptTouchEvent事件,此时ViewGroup和View的onTouchEvent都不消费事件
ACTION_DOWN:返回true,默认剩下的都是false,下同

12-13 16:39:40.641 20803-20803/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-13 16:39:40.641 20803-20803/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_DOWN12-13 16:39:40.641 20803-20803/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_DOWN

ACTION_MOVE:返回true

12-13 16:44:15.970 21229-21229/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-13 16:44:15.970 21229-21229/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_DOWN12-13 16:44:15.970 21229-21229/com.xiey94.scoller E/TAG: View-dispatchTouchEvent-ACTION_DOWN12-13 16:44:15.970 21229-21229/com.xiey94.scoller E/TAG: View-onTouchEvent-ACTION_DOWN12-13 16:44:15.970 21229-21229/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_DOWN

ACTION_UP:返回true

12-13 16:47:01.094 21437-21437/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-13 16:47:01.094 21437-21437/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_DOWN12-13 16:47:01.094 21437-21437/com.xiey94.scoller E/TAG: View-dispatchTouchEvent-ACTION_DOWN12-13 16:47:01.094 21437-21437/com.xiey94.scoller E/TAG: View-onTouchEvent-ACTION_DOWN12-13 16:47:01.094 21437-21437/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_DOWN

结论:
1、在down的时候拦截,则消费本身的onTouchEvent,但是在onTouchEvent的down中返回了false则上传;
2、在move的时候拦截,则在down中不拦截,在子View转一圈,最后子View不消费返回false,则直接返回到了ViewGroup的onTouchEvent中,因为返回false则事件上传,所以在move中设置并没有作用;
3、up中同样如此。

6、ViewGroup的onInterceptTouchEvent事件,此时ViewGroup中消费事件
ACTION都不拦截

12-13 17:09:45.457 23630-23630/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-13 17:09:45.457 23630-23630/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_DOWN12-13 17:09:45.457 23630-23630/com.xiey94.scoller E/TAG: View-dispatchTouchEvent-ACTION_DOWN12-13 17:09:45.457 23630-23630/com.xiey94.scoller E/TAG: View-onTouchEvent-ACTION_DOWN12-13 17:09:45.457 23630-23630/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_DOWN12-13 17:09:45.487 23630-23630/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_MOVE12-13 17:09:45.487 23630-23630/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_MOVE12-13 17:09:45.516 23630-23630/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_UP12-13 17:09:45.517 23630-23630/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_UP

1、都不拦截的时候,事件在子View那转一圈后回到ViewGroup的onTouchEvent中来了

down拦截

12-13 17:14:06.604 23838-23838/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-13 17:14:06.604 23838-23838/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_DOWN12-13 17:14:06.604 23838-23838/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_DOWN12-13 17:14:06.625 23838-23838/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_MOVE12-13 17:14:06.625 23838-23838/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_MOVE12-13 17:14:06.684 23838-23838/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_UP12-13 17:14:06.684 23838-23838/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_UP

2、down中拦截了,就去ViewGroup的onTouchEvent中了,后续的事件都由他来处理,剩下的action拦不拦截都无所谓

down中不拦截,剩下的拦截

12-13 17:22:21.288 25122-25122/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-13 17:22:21.288 25122-25122/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_DOWN12-13 17:22:21.288 25122-25122/com.xiey94.scoller E/TAG: View-dispatchTouchEvent-ACTION_DOWN12-13 17:22:21.288 25122-25122/com.xiey94.scoller E/TAG: View-onTouchEvent-ACTION_DOWN12-13 17:22:21.288 25122-25122/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_DOWN12-13 17:22:21.308 25122-25122/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_MOVE12-13 17:22:21.308 25122-25122/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_MOVE12-13 17:22:21.378 25122-25122/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_UP12-13 17:22:21.378 25122-25122/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_UP

3、由于一开始down中不拦截,所以去子View中转了一圈回到了ViewGroup的onTouchEvent中来了,这时候已经无关拦截了。

7、ViewGroup的onInterceptTouchEvent事件,此时View中消费事件
都不拦截:

12-13 17:25:31.032 25385-25385/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-13 17:25:31.032 25385-25385/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_DOWN12-13 17:25:31.032 25385-25385/com.xiey94.scoller E/TAG: View-dispatchTouchEvent-ACTION_DOWN12-13 17:25:31.032 25385-25385/com.xiey94.scoller E/TAG: View-onTouchEvent-ACTION_DOWN12-13 17:25:31.054 25385-25385/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_MOVE12-13 17:25:31.054 25385-25385/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_MOVE12-13 17:25:31.054 25385-25385/com.xiey94.scoller E/TAG: View-dispatchTouchEvent-ACTION_MOVE12-13 17:25:31.054 25385-25385/com.xiey94.scoller E/TAG: View-onTouchEvent-ACTION_MOVE12-13 17:25:31.091 25385-25385/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_UP12-13 17:25:31.091 25385-25385/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_UP12-13 17:25:31.091 25385-25385/com.xiey94.scoller E/TAG: View-dispatchTouchEvent-ACTION_UP12-13 17:25:31.092 25385-25385/com.xiey94.scoller E/TAG: View-onTouchEvent-ACTION_UP

1、这个结果看起来比较全面啊,解析一下:点进来,down不拦截进入子View的dispatchTouchEvent中,子View的dispatchTouchEvent中分发首先进入down中,进入onTouchEvent中的down,处理后返回true,然后ViewGroup的dispatchTouchEvent继续分发剩下的事件,一直消费结束。

down中拦截:

12-13 17:33:11.032 25858-25858/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-13 17:33:11.032 25858-25858/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_DOWN12-13 17:33:11.032 25858-25858/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_DOWN

2、意料之中,都拦截了又不处理只能上传

在move中拦截:

12-13 17:34:35.213 26021-26021/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-13 17:34:35.213 26021-26021/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_DOWN12-13 17:34:35.213 26021-26021/com.xiey94.scoller E/TAG: View-dispatchTouchEvent-ACTION_DOWN12-13 17:34:35.213 26021-26021/com.xiey94.scoller E/TAG: View-onTouchEvent-ACTION_DOWN12-13 17:34:35.238 26021-26021/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_MOVE12-13 17:34:35.238 26021-26021/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_MOVE12-13 17:34:35.255 26021-26021/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_MOVE12-13 17:34:35.255 26021-26021/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_MOVE12-13 17:34:35.345 26021-26021/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_UP12-13 17:34:35.345 26021-26021/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_UP

3、down不拦截就到了子View的down,在move中拦截了,子View就去不了了,拦截后就直接到了ViewGroup的onTouchEvent上午move中,后同

12-13 17:41:54.944 26385-26385/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-13 17:41:54.944 26385-26385/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_DOWN12-13 17:41:54.944 26385-26385/com.xiey94.scoller E/TAG: View-dispatchTouchEvent-ACTION_DOWN12-13 17:41:54.944 26385-26385/com.xiey94.scoller E/TAG: View-onTouchEvent-ACTION_DOWN12-13 17:41:54.974 26385-26385/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_MOVE12-13 17:41:54.974 26385-26385/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_MOVE12-13 17:41:55.024 26385-26385/com.xiey94.scoller E/TAG: View-dispatchTouchEvent-ACTION_MOVE12-13 17:41:55.024 26385-26385/com.xiey94.scoller E/TAG: View-onTouchEvent-ACTION_MOVE12-13 17:41:55.024 26385-26385/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_UP12-13 17:41:55.024 26385-26385/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_UP

但是我有一个疑问,子View在onTouchEvent中处理完down事件后,又是怎样到了ViewGroup的dispatchTouchEvent中的move中去的?
目前只知道分发完down事件之后如果返回false则会继续分发后续事件move、up的

都称呼手指点上去叫做点击事件,我觉得说的更详细一点应该叫做点击事件流,毕竟他是经过DOWN、MOVE、UP等事件组成的,有的ViewGroup在做事件拦截的时候,可能只是拦截了MOVE事件,它的DOWN事件可能在子View的onTouchEvent中的DOWN中处理了,而MOVE事件乃至UP事件是在ViewGroup中处理的,所以这样来说应该更好分析理解一点。

FLAG_DISALLOW_INTERCEPT这个标志位我不太懂:
大多讲解是,在requestDisallowInterceptTouchEvent中设置这个标签位后,将无法拦截除了ACTION_DOWN以外的其他点击事件,因为在ACTION_DOWN中重置了标签位

final int action = ev.getAction();final int actionMasked = action & MotionEvent.ACTION_MASK;// Handle an initial 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.    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); // restore action in case it was changed    } else {        intercepted = false;    }} else {    intercepted = true;}

也就是这段代码,看的我很迷惑,从上往下,如果事件为down,则重置标签位,
而这个标签位的含义为:不允许拦截
那重置后就为允许拦截
所以在down中会调用自己的onInterceptTouchEvent方法来判断是否需要拦截,
如果拦截,后面也没什么好说的,
如果不拦截,intercepted = false,
但是这这只是down事件,还有move和up事件呢,当再次分发down事件的时候,intercepted = true恒定不变,也就是都拦截,
那重置这个标签位有什么作用?不是说重置之后都不拦截吗?

简直难过的不行,怎么就分析不出来呢?
又重新看了一下代码,突然,看到另一个属性

if (actionMasked == MotionEvent.ACTION_DOWN|| mFirstTouchTarget != null) {

什么眼神啊,拆开看

actionMasked == MotionEvent.ACTION_DOWN

||

mFirstTouchTarget != null

我始终只看到了第一个DOWN事件,误认为这个只是在DOWN中执行的代码
为什么要在判断条件中唯独添加

actionMasked == MotionEvent.ACTION_DOWN

DOWN事件的判断呢,应该在分发之前mFirstTouchTarget是恒为null的,这样如果没有down事件的判断则永久进入不了这个判断条件里面
岔开一个:什么时候才能进入这个判断条件的else中呢,也就是

intercepted = true;

那就要两个判断条件都为false才行,
那就要:第一次点,肯定是down,肯定要进入的,是否拦截不管;第二次进,就剩后一个条件了,此时只要没子View接受这个点击事件就达到了这个条件,默认拦截
再看一下这个“是否拦截不管”:询问自己的onInterceptTouchEvent方法,如果拦截则那两个条件都不成立,则

intercepted = true;

恒定,如果不拦截,如果点击事件没有子View接受则两个条件都不成立,也是恒为

intercepted = true;

如果有子View接受,那就另外处理了
这里岔回来;
当点击之后,后面一个条件成立,如果拦截则恒定拦截,如果不拦截,也就是上面的“另外处理”了,假设此时标签位不变,则走的是down的老路,询问自己的onInterceptTouchEvent方法,判断是否拦截;如果此时改变了标签位,也就是

requestDisallowInterceptTouchEvent(true);

则直接:

intercepted = false;

恒定
也就是父类不允许拦截了。

写的可能有点乱,应该有点乱,这里再梳理一下:

还是之前说的那个问题,手指触摸应该叫做点击事件流,而不应该叫做点击事件。毕竟他都是由down、move、up等事件组成的,给出我的测试代码:

ViewGroup:

package com.xiey94.scoller;import android.content.Context;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.widget.LinearLayout;/** * @author xiey * @date created at 2017/12/13 15:48 * @package com.xiey94.scoller * @project Retrofit2 * @email xiey94@qq.com * @motto Why should our days leave us never to return? */public class TestLayout extends LinearLayout {    public TestLayout(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.e("TAG", "ViewGroup-dispatchTouchEvent-ACTION_DOWN");//                if (true) return true;                break;            case MotionEvent.ACTION_MOVE:                Log.e("TAG", "ViewGroup-dispatchTouchEvent-ACTION_MOVE");//                if (true) return true;                break;            case MotionEvent.ACTION_UP:                Log.e("TAG", "ViewGroup-dispatchTouchEvent-ACTION_UP");                break;            default:                break;        }        return super.dispatchTouchEvent(ev);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.e("TAG", "ViewGroup-onInterceptTouchEvent-ACTION_DOWN");//                if (true) return true;                break;            case MotionEvent.ACTION_MOVE:                Log.e("TAG", "ViewGroup-onInterceptTouchEvent-ACTION_MOVE");//                if (true) return true;                break;            case MotionEvent.ACTION_UP:                Log.e("TAG", "ViewGroup-onInterceptTouchEvent-ACTION_UP");//                if (true) return true;                break;            default:                break;        }        return super.onInterceptTouchEvent(ev);    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.e("TAG", "ViewGroup-onTouchEvent-ACTION_DOWN");                break;            case MotionEvent.ACTION_MOVE:                Log.e("TAG", "ViewGroup-onTouchEvent-ACTION_MOVE");                break;            case MotionEvent.ACTION_UP:                Log.e("TAG", "ViewGroup-onTouchEvent-ACTION_UP");                break;            default:                break;        }        return true;    }}

View

package com.xiey94.scoller;import android.content.Context;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;/** * @author xiey * @date created at 2017/12/13 9:45 * @package com.xiey94.scoller * @project Retrofit2 * @email xiey94@qq.com * @motto Why should our days leave us never to return? */public class TestView extends View {    public TestView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.e("TAG", "View-dispatchTouchEvent-ACTION_DOWN");                break;            case MotionEvent.ACTION_MOVE:                Log.e("TAG", "View-dispatchTouchEvent-ACTION_MOVE");                break;            case MotionEvent.ACTION_UP:                Log.e("TAG", "View-dispatchTouchEvent-ACTION_UP");                break;            default:                break;        }        return super.dispatchTouchEvent(ev);    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.e("TAG", "View-onTouchEvent-ACTION_DOWN");                break;            case MotionEvent.ACTION_MOVE:                Log.e("TAG", "View-onTouchEvent-ACTION_MOVE");//                if (true) return true;                break;            case MotionEvent.ACTION_UP:                Log.e("TAG", "View-onTouchEvent-ACTION_UP");                break;            default:                break;        }        return super.onTouchEvent(ev);    }}

为了通俗易懂,我就只说ViewGroup和View,不说他们的上下;
但是我先说一下,一个通识,当事件从Activity的dispatchTouchEvent开始分发时,一直到最终子View,如果都不处理,将层层返回到Activity的onTouchEvent中,怎么做到的:
Activity#dispatchTouchEvent

public boolean dispatchTouchEvent(MotionEvent ev) {        if (ev.getAction() == MotionEvent.ACTION_DOWN) {            onUserInteraction();        }        if (getWindow().superDispatchTouchEvent(ev)) {            return true;        }        return onTouchEvent(ev);    }

getWindow().superDispatchTouchEvent(ev)

中进行事件分发,层层分发下去,如果都不处理就一路往上返回false,最终在这里面执行Activity的onTouchEvent

好,就到这里。

从ViewGroup中的dispatchTouchEvent中开始,
触发ViewGroup的dispatchTouchEvent中的down,在down中判断是否拦截down,
如果拦截则去ViewGroup中的onTouchEvent的down中,如果返回false则整个事件流结束(也就是上传)。返回true则继续dispatchTouchevent的move中,此时默认拦截,进入ViewGroup的onTouchEvent的move中,返回false或者true好像效果都一样,都会触发dispatchTouchevent的up事件???
如果不拦截dispatchTouchEvent中的down,则进入子View,如果子View中的onTouchEvent(忽略onTouchListener)的down返回false则回传到ViewGroup的onTouchEvent,这时如果ViewGroup的onTouchEvent的down返回false,则到此结束,返回true,则进入ViewGroup的onTouchEvent的move中,返回false或者true好像效果都一样,都会触发dispatchTouchevent的up事件???

尝试解释上面的问题:当一个move事件返回false的时候,一直往上传,最后传到了Activity的move中,这时又触发了下一个move,但又是这种结果,手松开时触发了up,这就不是很明白了,不是应该只有上一个返回true的时候才会触发下一个吗?

触发ViewGroup的dispatchTouchEvent中的move,在move中判断是否拦截move,都到了这个地步,说明第一个中没有拦截,既然第一个没有拦截,那就到不了这一步,他会在子View中转一圈后直接回到ViewGroup的onTouchEvent中,up同理。

所以,最终还是有点迷惑,还需要好好思考一下。

零星补充:

1、假设ViewGroup B没有拦截DOWN事件(还是View C来处理DOWN事件),但它拦截了接下来的MOVE事件。

DOWN事件传递到C的onTouchEvent方法,返回了true。
在后续到来的MOVE事件,B的onInterceptTouchEvent方法返回true拦截该MOVE事件,但该事件并没有传递给B;这个MOVE事件将会被系统变成一个CANCEL事件传递给C的onTouchEvent方法
后续又来了一个MOVE事件,该MOVE事件才会直接传递给B的onTouchEvent()

对于这个突发事件,本来我觉得只能作为一个知识点了解一下,然后今天突然醒悟过来,它是可以用的,我做了一个代码测试,一个ListView可上下滑动,item可左右滑动(粗糙版的QQ好友聊天列表),后面跟着置顶,删除等按钮;本来处理的是:在上下滑动的时候,ListView拦截处理,然后左右滑动的时候,ListView不拦截,item处理,在我用scroller进行滚动的时候,如果滚动的时候比较快,就会带出item右边的空白(就像你拉扯LScrollView的时候,上面会留白),如果正常弹回去也就算了,本来处理是可以的,毕竟做了边界值判断,但是在这一瞬间做了上下滑动,然后那个留白还没弹回去就将事件的处理权交给了ListView,然后保存着留白上下滚动,丑的不行。我开始想的是在ListView中做拦截的时候传入一个接口方法,便于item做善后处理,然后这样代码看起来就比较恶心了,也不是我的目的(其实还没实现,写到一半的时候就忍受不了,怎么可以这样处理,那还不如不处理,然后今天突然又留意了这边,这不就是我的那个“接口方法”吗)。

在查看了众多博客之后,我只能臆断一下:在ViewGroup中的down中做了拦截,然后事件到了ViewGroup的onTouchEvent中的down,并返回true消费。(此时子View并不强制要求父ViewGroup不拦截事件,则父ViewGroup默认拦截剩下的所有事件)在MOVE事件到来的时候,默认拦截并到了onTouchEvent的move中,结论就在这里诞生了:在我目前所描述的情况下,只要你down事件敢消费,那么剩下的事件你都得给我吞了,没有退回去的事。

还没完,我就知道事情没那么简单:我从头看到尾,终究是漏掉了一个大boss,Activity,事件是从Activity中分发下来的,而我的学习研究过程中为了简化那些流程,所以省略了Activity中的分析,然后今天测试了一下Activity的关于我上面的那个臆断,发现完全是错的。
在我上述描述的情况中(我还是贴一下代码):
activity_main:

<?xml version="1.0" encoding="utf-8"?><com.xiey94.scoller.Test2Layout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <com.xiey94.scoller.TestLayout        android:layout_width="match_parent"        android:layout_height="match_parent">        <com.xiey94.scoller.TestView            android:layout_width="match_parent"            android:layout_height="match_parent" />    </com.xiey94.scoller.TestLayout></com.xiey94.scoller.Test2Layout>

嵌套两个ViewGroup,一个子View

MainActivity.java

package com.xiey94.scoller;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.view.MotionEvent;import android.view.WindowManager;public class MainActivity extends AppCompatActivity {    private TestListView listView;    private TestAdapter adapter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);        setContentView(R.layout.activity_main);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.e("TAG", "Activity-onTouchEvent-ACTION_DOWN");                break;            case MotionEvent.ACTION_MOVE:                Log.e("TAG", "Activity-onTouchEvent-ACTION_MOVE");                break;            case MotionEvent.ACTION_UP:                Log.e("TAG", "Activity-onTouchEvent-ACTION_UP");                break;            default:                break;        }        return super.onTouchEvent(event);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.e("TAG", "Activity-dispatchTouchEvent-ACTION_DOWN");                break;            case MotionEvent.ACTION_MOVE:                Log.e("TAG", "Activity-dispatchTouchEvent-ACTION_MOVE");                break;            case MotionEvent.ACTION_UP:                Log.e("TAG", "Activity-dispatchTouchEvent-ACTION_UP");                break;            default:                break;        }        return super.dispatchTouchEvent(ev);    }}

两个事件进行打印Log(这里面怎么没有拦截方法呢?都说他是第一个触发并接收到事件的,要个毛的拦截方法啊):
Test2Layout.java

package com.xiey94.scoller;import android.content.Context;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.widget.LinearLayout;/** * @author xiey * @date created at 2017/12/14 9:26 * @package com.xiey94.scoller * @project Retrofit2 * @email xiey94@qq.com * @motto Why should our days leave us never to return? */public class Test2Layout extends LinearLayout {    public Test2Layout(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.e("TAG", "ViewGroup2-dispatchTouchEvent-ACTION_DOWN");                break;            case MotionEvent.ACTION_MOVE:                Log.e("TAG", "ViewGroup2-dispatchTouchEvent-ACTION_MOVE");                break;            case MotionEvent.ACTION_UP:                Log.e("TAG", "ViewGroup2-dispatchTouchEvent-ACTION_UP");                break;            default:                break;        }        return super.dispatchTouchEvent(ev);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.e("TAG", "ViewGroup2-onInterceptTouchEvent-ACTION_DOWN");                break;            case MotionEvent.ACTION_MOVE:                Log.e("TAG", "ViewGroup2-onInterceptTouchEvent-ACTION_MOVE");                break;            case MotionEvent.ACTION_UP:                Log.e("TAG", "ViewGroup2-onInterceptTouchEvent-ACTION_UP");                break;            default:                break;        }        return super.onInterceptTouchEvent(ev);    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.e("TAG", "ViewGroup2-onTouchEvent-ACTION_DOWN");                break;            case MotionEvent.ACTION_MOVE:                Log.e("TAG", "ViewGroup2-onTouchEvent-ACTION_MOVE");                break;            case MotionEvent.ACTION_UP:                Log.e("TAG", "ViewGroup2-onTouchEvent-ACTION_UP");                break;            case MotionEvent.ACTION_CANCEL:                Log.e("TAG", "ViewGroup2-onTouchEvent-ACTION_CANCEL");                break;            default:                break;        }        return true;    }}

这个是xml中最外面的那个ViewGroup,里面也是三个方法并打印Log,唯一做了处理的就是在onTouchEvent中返回了true,但是他并没有拦截。所以他处理事件的唯一可能性就是子View都不处理回传到他那

TestLayout.java

package com.xiey94.scoller;import android.content.Context;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.widget.LinearLayout;/** * @author xiey * @date created at 2017/12/13 15:48 * @package com.xiey94.scoller * @project Retrofit2 * @email xiey94@qq.com * @motto Why should our days leave us never to return? */public class TestLayout extends LinearLayout {    public TestLayout(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.e("TAG", "ViewGroup-dispatchTouchEvent-ACTION_DOWN");//                if (true) return true;                break;            case MotionEvent.ACTION_MOVE:                Log.e("TAG", "ViewGroup-dispatchTouchEvent-ACTION_MOVE");//                if (true) return true;                break;            case MotionEvent.ACTION_UP:                Log.e("TAG", "ViewGroup-dispatchTouchEvent-ACTION_UP");                break;            default:                break;        }        return super.dispatchTouchEvent(ev);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.e("TAG", "ViewGroup-onInterceptTouchEvent-ACTION_DOWN");                if (true) return true;                break;            case MotionEvent.ACTION_MOVE:                Log.e("TAG", "ViewGroup-onInterceptTouchEvent-ACTION_MOVE");//                if (true) return true;                break;            case MotionEvent.ACTION_UP:                Log.e("TAG", "ViewGroup-onInterceptTouchEvent-ACTION_UP");//                if (true) return true;                break;            default:                break;        }        return super.onInterceptTouchEvent(ev);    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.e("TAG", "ViewGroup-onTouchEvent-ACTION_DOWN");                if (true) return false;                break;            case MotionEvent.ACTION_MOVE:                Log.e("TAG", "ViewGroup-onTouchEvent-ACTION_MOVE");                if (true) return false;                break;            case MotionEvent.ACTION_UP:                Log.e("TAG", "ViewGroup-onTouchEvent-ACTION_UP");                if (true) return false;            case MotionEvent.ACTION_CANCEL:                Log.e("TAG", "ViewGroup-onTouchEvent-ACTION_CANCEL");                if (true) return false;                break;            default:                break;        }        return super.onTouchEvent(ev);    }}

这是嵌套的第二个ViewGroup,主要的处理就在这里:
1、都打印Log;
2、在它的onInterceptTouchEvent的Action-down中进行拦截,然后在onTouchEvent的action-down中返回返回false;

打印日志:

12-15 10:56:50.951 17467-17467/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_DOWN12-15 10:56:50.952 17467-17467/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_DOWN12-15 10:56:50.952 17467-17467/com.xiey94.scoller E/TAG: ViewGroup2-onInterceptTouchEvent-ACTION_DOWN12-15 10:56:50.952 17467-17467/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-15 10:56:50.952 17467-17467/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_DOWN12-15 10:56:50.952 17467-17467/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_DOWN12-15 10:56:50.952 17467-17467/com.xiey94.scoller E/TAG: ViewGroup2-onTouchEvent-ACTION_DOWN12-15 10:56:50.972 17467-17467/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_MOVE12-15 10:56:50.973 17467-17467/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_MOVE12-15 10:56:50.973 17467-17467/com.xiey94.scoller E/TAG: ViewGroup2-onTouchEvent-ACTION_MOVE12-15 10:56:50.988 17467-17467/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_MOVE12-15 10:56:50.988 17467-17467/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_MOVE12-15 10:56:50.988 17467-17467/com.xiey94.scoller E/TAG: ViewGroup2-onTouchEvent-ACTION_MOVE12-15 10:56:50.993 17467-17467/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_UP12-15 10:56:50.994 17467-17467/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_UP12-15 10:56:50.994 17467-17467/com.xiey94.scoller E/TAG: ViewGroup2-onTouchEvent-ACTION_UP

分析:意料之中,从Activity开始分发,到了Test2Layout的分发,然后拦截(他并没有拦截,只是事件流经过这里),以上全处于不作为状态,然后就到了TestLayout,他在down中拦截了,所以事件就交给了它的onTouchEvent的action-down中处理,但是转一圈返现他返回false,这个down事件并没有消费掉,只能往上传,到了Test2Layout的onTouchEvent的down中,我们在这里返回了true,所以down事件在这里消费了,事件戛然而止;然后开始MOVE事件,一样的分发过来,由于TestLayout的拦截不处理作为,源码里面做了设置,这里我就不去寻找了,(我见过,嘿嘿),以后事件就只到Test2Layout中了,剩下的都这样,都在Test2Layout中消费了。

以上是在意料之中的,所以不意外,现在改一个条件,将TestLayout中onTouchEvent中的action-down中返回true,action-move也返回true,avtion-up也返回true,

12-15 11:06:31.721 18043-18043/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_DOWN12-15 11:06:31.721 18043-18043/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_DOWN12-15 11:06:31.721 18043-18043/com.xiey94.scoller E/TAG: ViewGroup2-onInterceptTouchEvent-ACTION_DOWN12-15 11:06:31.722 18043-18043/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-15 11:06:31.722 18043-18043/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_DOWN12-15 11:06:31.722 18043-18043/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_DOWN12-15 11:06:31.740 18043-18043/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_MOVE12-15 11:06:31.740 18043-18043/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_MOVE12-15 11:06:31.740 18043-18043/com.xiey94.scoller E/TAG: ViewGroup2-onInterceptTouchEvent-ACTION_MOVE12-15 11:06:31.740 18043-18043/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_MOVE12-15 11:06:31.740 18043-18043/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_MOVE12-15 11:06:31.749 18043-18043/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_MOVE12-15 11:06:31.749 18043-18043/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_MOVE12-15 11:06:31.749 18043-18043/com.xiey94.scoller E/TAG: ViewGroup2-onInterceptTouchEvent-ACTION_MOVE12-15 11:06:31.749 18043-18043/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_MOVE12-15 11:06:31.749 18043-18043/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_MOVE12-15 11:06:31.749 18043-18043/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_UP12-15 11:06:31.750 18043-18043/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_UP12-15 11:06:31.750 18043-18043/com.xiey94.scoller E/TAG: ViewGroup2-onInterceptTouchEvent-ACTION_UP12-15 11:06:31.750 18043-18043/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_UP12-15 11:06:31.750 18043-18043/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_UP

这里几乎都不用分析,处于能理解的正常范畴,在Testlayout中做了拦截,然后消费了事件。

最后就到了我纠结的问题了:
将TestLayout中onTouchEvent中的action-down中返回true,action-move返回false,avtion-up返回true

12-15 11:08:57.447 18265-18265/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_DOWN12-15 11:08:57.448 18265-18265/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_DOWN12-15 11:08:57.448 18265-18265/com.xiey94.scoller E/TAG: ViewGroup2-onInterceptTouchEvent-ACTION_DOWN12-15 11:08:57.448 18265-18265/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-15 11:08:57.448 18265-18265/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_DOWN12-15 11:08:57.448 18265-18265/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_DOWN12-15 11:08:57.473 18265-18265/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_MOVE12-15 11:08:57.473 18265-18265/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_MOVE12-15 11:08:57.473 18265-18265/com.xiey94.scoller E/TAG: ViewGroup2-onInterceptTouchEvent-ACTION_MOVE12-15 11:08:57.473 18265-18265/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_MOVE12-15 11:08:57.473 18265-18265/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_MOVE12-15 11:08:57.473 18265-18265/com.xiey94.scoller E/TAG: Activity-onTouchEvent-ACTION_MOVE12-15 11:08:57.483 18265-18265/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_MOVE12-15 11:08:57.484 18265-18265/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_MOVE12-15 11:08:57.484 18265-18265/com.xiey94.scoller E/TAG: ViewGroup2-onInterceptTouchEvent-ACTION_MOVE12-15 11:08:57.484 18265-18265/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_MOVE12-15 11:08:57.484 18265-18265/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_MOVE12-15 11:08:57.484 18265-18265/com.xiey94.scoller E/TAG: Activity-onTouchEvent-ACTION_MOVE12-15 11:08:57.485 18265-18265/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_UP12-15 11:08:57.485 18265-18265/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_UP12-15 11:08:57.485 18265-18265/com.xiey94.scoller E/TAG: ViewGroup2-onInterceptTouchEvent-ACTION_UP12-15 11:08:57.485 18265-18265/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_UP12-15 11:08:57.485 18265-18265/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_UP

先不分析这个,将TestLayout中onTouchEvent中的action-down中返回true,action-move返回false,avtion-up返回false

12-15 11:10:43.579 18460-18460/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_DOWN12-15 11:10:43.579 18460-18460/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_DOWN12-15 11:10:43.579 18460-18460/com.xiey94.scoller E/TAG: ViewGroup2-onInterceptTouchEvent-ACTION_DOWN12-15 11:10:43.580 18460-18460/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-15 11:10:43.580 18460-18460/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_DOWN12-15 11:10:43.580 18460-18460/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_DOWN12-15 11:10:43.605 18460-18460/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_MOVE12-15 11:10:43.605 18460-18460/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_MOVE12-15 11:10:43.605 18460-18460/com.xiey94.scoller E/TAG: ViewGroup2-onInterceptTouchEvent-ACTION_MOVE12-15 11:10:43.605 18460-18460/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_MOVE12-15 11:10:43.605 18460-18460/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_MOVE12-15 11:10:43.605 18460-18460/com.xiey94.scoller E/TAG: Activity-onTouchEvent-ACTION_MOVE12-15 11:10:43.610 18460-18460/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_UP12-15 11:10:43.610 18460-18460/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_UP12-15 11:10:43.610 18460-18460/com.xiey94.scoller E/TAG: ViewGroup2-onInterceptTouchEvent-ACTION_UP12-15 11:10:43.610 18460-18460/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_UP12-15 11:10:43.610 18460-18460/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_UP12-15 11:10:43.610 18460-18460/com.xiey94.scoller E/TAG: Activity-onTouchEvent-ACTION_UP

将这两个Log合一块分析:第一个中,action-down和action-up和之前一样,处于能理解的范畴,都是接收到了事件并消费了事件;然后就到了关键之处,我在第一个中action-move中返回了false,按照理解,应该事件返回到Test2Layout的action-move中去处理,但是结果并不是这样,好像事件根本就没有冒泡回传,而是直接就到了Activity的onTouchEvent的action-move中去处理了,第二个中的现象也是这样,这就匪夷所思了,当我返回false的时候,源码到底做了什么处理,当我一个事件想上下两个View处理的时候就中断了,而是直接就传递给了Activity中。

于是我猜想会不会只是跳过了Test2Layout这层,而我的层级不够,于是我贼心不死的又嵌套了一层

<?xml version="1.0" encoding="utf-8"?><com.xiey94.scoller.Test3Layout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <com.xiey94.scoller.Test2Layout        android:layout_width="match_parent"        android:layout_height="match_parent">        <com.xiey94.scoller.TestLayout            android:layout_width="match_parent"            android:layout_height="match_parent">            <com.xiey94.scoller.TestView                android:layout_width="match_parent"                android:layout_height="match_parent" />        </com.xiey94.scoller.TestLayout>    </com.xiey94.scoller.Test2Layout></com.xiey94.scoller.Test3Layout>
package com.xiey94.scoller;import android.content.Context;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.widget.LinearLayout;/** * @author xiey * @date created at 2017/12/14 9:26 * @package com.xiey94.scoller * @project Retrofit2 * @email xiey94@qq.com * @motto Why should our days leave us never to return? */public class Test3Layout extends LinearLayout {    public Test3Layout(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.e("TAG", "ViewGroup3-dispatchTouchEvent-ACTION_DOWN");                break;            case MotionEvent.ACTION_MOVE:                Log.e("TAG", "ViewGroup3-dispatchTouchEvent-ACTION_MOVE");                break;            case MotionEvent.ACTION_UP:                Log.e("TAG", "ViewGroup3-dispatchTouchEvent-ACTION_UP");                break;            default:                break;        }        return super.dispatchTouchEvent(ev);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.e("TAG", "ViewGroup3-onInterceptTouchEvent-ACTION_DOWN");                break;            case MotionEvent.ACTION_MOVE:                Log.e("TAG", "ViewGroup3-onInterceptTouchEvent-ACTION_MOVE");                break;            case MotionEvent.ACTION_UP:                Log.e("TAG", "ViewGroup3-onInterceptTouchEvent-ACTION_UP");                break;            default:                break;        }        return super.onInterceptTouchEvent(ev);    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.e("TAG", "ViewGroup3-onTouchEvent-ACTION_DOWN");                break;            case MotionEvent.ACTION_MOVE:                Log.e("TAG", "ViewGroup3-onTouchEvent-ACTION_MOVE");                break;            case MotionEvent.ACTION_UP:                Log.e("TAG", "ViewGroup3-onTouchEvent-ACTION_UP");                break;            case MotionEvent.ACTION_CANCEL:                Log.e("TAG", "ViewGroup3-onTouchEvent-ACTION_CANCEL");                break;            default:                break;        }        return super.onTouchEvent(ev);    }}

最外层中什么都不做,只是打印Log,

12-15 11:21:53.827 19133-19133/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_DOWN12-15 11:21:53.828 19133-19133/com.xiey94.scoller E/TAG: ViewGroup3-dispatchTouchEvent-ACTION_DOWN12-15 11:21:53.828 19133-19133/com.xiey94.scoller E/TAG: ViewGroup3-onInterceptTouchEvent-ACTION_DOWN12-15 11:21:53.828 19133-19133/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_DOWN12-15 11:21:53.828 19133-19133/com.xiey94.scoller E/TAG: ViewGroup2-onInterceptTouchEvent-ACTION_DOWN12-15 11:21:53.828 19133-19133/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_DOWN12-15 11:21:53.828 19133-19133/com.xiey94.scoller E/TAG: ViewGroup-onInterceptTouchEvent-ACTION_DOWN12-15 11:21:53.828 19133-19133/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_DOWN12-15 11:21:53.850 19133-19133/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_MOVE12-15 11:21:53.850 19133-19133/com.xiey94.scoller E/TAG: ViewGroup3-dispatchTouchEvent-ACTION_MOVE12-15 11:21:53.850 19133-19133/com.xiey94.scoller E/TAG: ViewGroup3-onInterceptTouchEvent-ACTION_MOVE12-15 11:21:53.850 19133-19133/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_MOVE12-15 11:21:53.850 19133-19133/com.xiey94.scoller E/TAG: ViewGroup2-onInterceptTouchEvent-ACTION_MOVE12-15 11:21:53.850 19133-19133/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_MOVE12-15 11:21:53.850 19133-19133/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_MOVE12-15 11:21:53.850 19133-19133/com.xiey94.scoller E/TAG: Activity-onTouchEvent-ACTION_MOVE12-15 11:21:53.971 19133-19133/com.xiey94.scoller E/TAG: Activity-dispatchTouchEvent-ACTION_UP12-15 11:21:53.971 19133-19133/com.xiey94.scoller E/TAG: ViewGroup3-dispatchTouchEvent-ACTION_UP12-15 11:21:53.972 19133-19133/com.xiey94.scoller E/TAG: ViewGroup3-onInterceptTouchEvent-ACTION_UP12-15 11:21:53.972 19133-19133/com.xiey94.scoller E/TAG: ViewGroup2-dispatchTouchEvent-ACTION_UP12-15 11:21:53.972 19133-19133/com.xiey94.scoller E/TAG: ViewGroup2-onInterceptTouchEvent-ACTION_UP12-15 11:21:53.972 19133-19133/com.xiey94.scoller E/TAG: ViewGroup-dispatchTouchEvent-ACTION_UP12-15 11:21:53.972 19133-19133/com.xiey94.scoller E/TAG: ViewGroup-onTouchEvent-ACTION_UP12-15 11:21:53.972 19133-19133/com.xiey94.scoller E/TAG: Activity-onTouchEvent-ACTION_UP

但是结果依旧如此,还是直接就跳到了Activity的onTouchEvent中去了。

又是一个新问题,看来又要到源码中去找答案了,不过总算是冲出了一层。

原创粉丝点击