事件分发
来源:互联网 发布:共享无法启用网络发现 编辑:程序博客网 时间: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中去了。
又是一个新问题,看来又要到源码中去找答案了,不过总算是冲出了一层。
- 事件分发
- 事件分发
- 事件分发
- 事件分发
- 事件分发
- 事件分发
- 事件分发
- 事件分发
- 事件分发
- 事件分发
- 事件分发
- 事件分发
- 事件分发
- 事件分发
- 事件分发
- 事件分发
- 事件分发
- 事件分发
- 数据结构实验之查找五:平方之哈希表
- 工作中遇到的关于前端的那些事
- oracle权限
- jdk1.6,jdk1.7,jdk1.8安装共存问题。
- Bootstrap-table 表格计算列的和----总计
- 事件分发
- springBoot aop
- 19、Android开发基础之数据库的开发
- 多重继承
- js将一个数组分成二维数组
- svn error:could not read response body connection was closed by server
- 简单视频播放AVPlayer和AVPlayerViewController
- 《程序员的思维修炼:开发认知潜能的九堂课》【PDF】下载
- 报错ora-04098:触发器无效且未通过重新验证