ViewGroup的事件拦截、事件分发、事件处理
2017-07-11 14:30
471 查看
上篇博客说了下View的事件分发和事件处理,接着这里说下ViewGroup,ViewGroup多了一个事件拦截,涉及到有三个相应的方法;
先看下下面几种不同情况运行的结果;
正常情况:
ACTION_DOWN:
ViewGroup.dispatchTouchEvent—>ViewGroup.onInterceptTouchEvent—>View.dispatchTouchEvent—>View.onTouch—>View.onTouchEvent
ACTION_UP:
ViewGroup.dispatchTouchEvent—>ViewGroup.onInterceptTouchEvent—>View.dispatchTouchEvent—>View.onTouch—>View.onTouchEvent—>View.onClick
注释掉View.onClick
ACTION_DOWN:
ViewGroup.dispatchTouchEvent—>ViewGroup.onInterceptTouchEvent—>View.dispatchTouchEvent—>View.onTouch—>View.onTouchEvent—>ViewGroup.onTouchEvent
将View中的onTouchEvent返回值改成true
ACTION_DOWN:
ViewGroup.dispatchTouchEvent—>ViewGroup.onInterceptTouchEvent—>View.dispatchTouchEvent—>View.onTouch—>View.onTouchEvent
ACTION_UP:
ViewGroup.dispatchTouchEvent—>ViewGroup.onInterceptTouchEvent—>View.dispatchTouchEvent—>View.onTouch—>View.onTouchEvent
将ViewGroup中的onInterceptTouchEvent返回值改成true
ACTION_DOWN:
ViewGroup.dispatchTouchEvent—>ViewGroup.onInterceptTouchEvent—>ViewGroup.onTouchEvent
结合上面的运行结果,点进ViewGroup源码去看看并分析下出现上面结果的原因;
点击源码找到dispatchTouchEvent()方法,
根据拿到的action来进行判断,为MotionEvent.ACTION_DOWN的时候首先调用cancelAndClearTouchTargets(ev);清除掉target
会走到clearTouchTargets()方法中将mFirstTouchTarget至为null;mFirstTouchTarget设置为null后,就定义了一个事件拦截的标识,模式是false,
如果事件没有被拦截掉的话,就是说intercepted为false的时候,就会调用这里,
走到这里的话,已经调用了ViewGroup.dispatchTouchEvent、ViewGroup.onInterceptTouchEvent、View.dispatchTouchEvent,到了View.dispatchTouchEvent,接着就会走View.onTouch、View.onTouchEvent、View.onClick这个在View的事件处理里面已经说过了,这个时候运行的就是第一个结果;
如果将View的点击事件屏蔽掉,performClick()方法返回的就是false,就是说没有消费事件,
将View中onTouchEvent的返回值改成true,在View的事件中已经详细说了,
将ViewGroup中onInterceptTouchEvent的返回值改成true,下面这个判断就不会走,
没有走,就不会调用dispatchTransformedTouchEvent方法,就不会去走View中的那些方法了;通过ViewGroup和View的源码知道:
如果说子View没有一个地方返回true,只会进来一次响应DOWN事件,代表不需要消费该事件,如果想响应MOVE,UP必须找个地方返回true
对于ViewGroup来说,如果想拦截子View的touch事件,重写onInterceptTouchEvent返回true即可
如果onInterceptTouchEvent返回的是true会执行ViewGroup的onTouchEvent方法,如果子view没有消费事件也会执行onTouchEvent方法
上面如有对ViewGroup的事件处理写的不对的地方,欢迎交流
dispatchTouchEvent 事件分发 onInterceptTouchEvent 事件拦截 onTouchEvent 事件处理
先看下下面几种不同情况运行的结果;
正常情况:
ACTION_DOWN:
ViewGroup.dispatchTouchEvent—>ViewGroup.onInterceptTouchEvent—>View.dispatchTouchEvent—>View.onTouch—>View.onTouchEvent
ACTION_UP:
ViewGroup.dispatchTouchEvent—>ViewGroup.onInterceptTouchEvent—>View.dispatchTouchEvent—>View.onTouch—>View.onTouchEvent—>View.onClick
注释掉View.onClick
ACTION_DOWN:
ViewGroup.dispatchTouchEvent—>ViewGroup.onInterceptTouchEvent—>View.dispatchTouchEvent—>View.onTouch—>View.onTouchEvent—>ViewGroup.onTouchEvent
将View中的onTouchEvent返回值改成true
ACTION_DOWN:
ViewGroup.dispatchTouchEvent—>ViewGroup.onInterceptTouchEvent—>View.dispatchTouchEvent—>View.onTouch—>View.onTouchEvent
ACTION_UP:
ViewGroup.dispatchTouchEvent—>ViewGroup.onInterceptTouchEvent—>View.dispatchTouchEvent—>View.onTouch—>View.onTouchEvent
将ViewGroup中的onInterceptTouchEvent返回值改成true
ACTION_DOWN:
ViewGroup.dispatchTouchEvent—>ViewGroup.onInterceptTouchEvent—>ViewGroup.onTouchEvent
结合上面的运行结果,点进ViewGroup源码去看看并分析下出现上面结果的原因;
点击源码找到dispatchTouchEvent()方法,
@Override public boolean dispatchTouchEvent(MotionEvent ev) { ... boolean handled = false; if (onFilterTouchEventForSecurity(ev)) { ... if (actionMasked == MotionEvent.ACTION_DOWN) { //清楚掉一些标记,主要是mFirstTouchTarget cancelAndClearTouchTargets(ev); resetTouchState(); } //intercepted用来标识事件拦截 默认是false final boolean intercepted; if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (!disallowIntercept) { //调用事件拦截方法,并返回值, intercepted = onInterceptTouchEvent(ev); ev.setAction(action); } else { intercepted = false; } } else { intercepted = true; } ... final boolean canceled = resetCancelNextUpFlag(this) || actionMasked == MotionEvent.ACTION_CANCEL; final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0; TouchTarget newTouchTarget = null; boolean alreadyDispatchedToNewTouchTarget = false; //intercepted为true也就是事件拦截那里返回为true就不会走这个if里面 if (!canceled && !intercepted) { ... if (actionMasked == MotionEvent.ACTION_DOWN || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { ... if (newTouchTarget == null && childrenCount != 0) { ... if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { 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; } ... } if (preorderedList != null) preorderedList.clear(); } ... } } if (mFirstTouchTarget == null) { handled = dispatchTransformedTouchEvent(ev, canceled, null, TouchTarget.ALL_POINTER_IDS); } else { ... } ... return handled; }
根据拿到的action来进行判断,为MotionEvent.ACTION_DOWN的时候首先调用cancelAndClearTouchTargets(ev);清除掉target
// 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(); }
/** * Clears all touch targets. */ private void clearTouchTargets() { TouchTarget target = mFirstTouchTarget; if (target != null) { do { TouchTarget next = target.next; target.recycle(); target = next; } while (target != null); mFirstTouchTarget = null; } }
会走到clearTouchTargets()方法中将mFirstTouchTarget至为null;mFirstTouchTarget设置为null后,就定义了一个事件拦截的标识,模式是false,
// Check for interception. final boolean intercepted;
如果事件没有被拦截掉的话,就是说intercepted为false的时候,就会调用这里,
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; }
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel, View child, int desiredPointerIdBits) { final boolean handled; // Canceling motions is a special case. We don't need to perform any transformations // or filtering. The important part is the action, not the contents. final int oldAction = event.getAction(); if (cancel || oldAction == MotionEvent.ACTION_CANCEL) { event.setAction(MotionEvent.ACTION_CANCEL); //如果child为null直接调用自己中的dispatchTouchEvent,否则调用子child中的dispatchTouchEvent if (child == null) { handled = super.dispatchTouchEvent(event); } else { handled = child.dispatchTouchEvent(event); } event.setAction(oldAction); return handled; } ... return handled; }
走到这里的话,已经调用了ViewGroup.dispatchTouchEvent、ViewGroup.onInterceptTouchEvent、View.dispatchTouchEvent,到了View.dispatchTouchEvent,接着就会走View.onTouch、View.onTouchEvent、View.onClick这个在View的事件处理里面已经说过了,这个时候运行的就是第一个结果;
如果将View的点击事件屏蔽掉,performClick()方法返回的就是false,就是说没有消费事件,
将View中onTouchEvent的返回值改成true,在View的事件中已经详细说了,
将ViewGroup中onInterceptTouchEvent的返回值改成true,下面这个判断就不会走,
if (!canceled && !intercepted){ ... }
没有走,就不会调用dispatchTransformedTouchEvent方法,就不会去走View中的那些方法了;通过ViewGroup和View的源码知道:
如果说子View没有一个地方返回true,只会进来一次响应DOWN事件,代表不需要消费该事件,如果想响应MOVE,UP必须找个地方返回true
对于ViewGroup来说,如果想拦截子View的touch事件,重写onInterceptTouchEvent返回true即可
如果onInterceptTouchEvent返回的是true会执行ViewGroup的onTouchEvent方法,如果子view没有消费事件也会执行onTouchEvent方法
上面如有对ViewGroup的事件处理写的不对的地方,欢迎交流
相关文章推荐
- ViewGroup触摸事件的分发,拦截,消耗(dispatchTouchEvent , onInterceptTouchEvent , onTouchEvent)
- view、viewgroup 事件响应拦截处理机制
- android view、viewgroup 事件响应拦截处理机制
- Android中View和ViewGroup事件分发拦截机制完美分析
- android下ViewGroup的事件分发和处理
- Android事件分发之子View驳回ViewGroup拦截原理分析
- Android View - 事件分发,拦截,处理机制
- android view、viewgroup 事件响应拦截处理机制
- ViewGroup事件分发处理
- Andriod 从源码的角度详解View,ViewGroup的Touch事件的分发机制
- View及ViewGroup的事件分发及传递(一)
- View及ViewGroup的事件分发及传递(二)
- 学习ViewGroup事件分发笔记(一)
- Andriod 从源码的角度详解View,ViewGroup的Touch事件的分发机制
- Andriod 从源码的角度详解View,ViewGroup的Touch事件的分发机制
- Android View、ViewGroup 事件分发机制(一)
- Android 事件分发机制之ViewGroup
- android ViewGroup和View触屏基础事件OnTouch处理
- Andriod 从源码的角度详解View,ViewGroup的Touch事件的分发机制
- ViewGroup如何分发事件