ViewGroup源码-Touch事件
在Android-27中查看源码:
在看完View源码的触摸事件(View源码-Touch事件)后,我们接着来看看容器类View的触摸事件。因为容器类的View都继承自ViewGroup,所以我们在ViewGroup的源码中来看看是如何处理触摸事件的。
同样的先来看ViewGroup源码中的dispatchTouchEvent方法:
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 { // There are no touch targets and this action is not an initial down // so this view group continues to intercept touches. intercepted = true; }
首先,会判断是否不允许拦截,可以通过requestDisallowInterceptTouchEvent进行设置,默认允许拦截。如果允许拦截,会调用onInterceptTouchEvent,看看该View是否拦截了触摸事件,默认不拦截即可以将触摸事件向子View传递。
接下来,如果触摸事件没有取消并且没有拦截,在手指按下的时候:
final ArrayList<View> preorderedList = buildTouchDispatchChildList(); ... for (int i = childrenCount - 1; i >= 0; i--){ ... 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; } ... }
- 按照绘制子View的顺序,找到该ViewGoup的所有子view,并保存到ArrayList中。
- 根据视图顺序依次遍历子View。判断当前子view是否是TouchTarget,若是则跳出循环。否则调用dispatchTransformedTouchEvent方法,如果当前子View的dispatchTouchEvent返回为true,找到该子View在ViewGroup中的index,并将该子View作为新的TouchTarget。
- 清楚保存了所有子View的ArrayList。
然后在TouchTarget形成的链式结构中,处理触摸事件:
// 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; } }
- 如果子View没有处理触摸事件,则由当前的ViewGroup处理,然后返回处理结果。因为ViewGroup是View的子类,所以还是由View的dispatchTouchEvent处理。
- 如果子View中处理了触摸事件,根据TouchTarget生成的链式结构,不断循环,分别调用里面View的dispatchTouchEvent方法。
从上面的分析可以看出整个ViewGroup的Touch事件的整个传递过程如下:
- 是否调用了requestDisallowInterceptTouchEvent方法设置不允许拦截,默认允许拦截。若允许拦截,则再调用onInterceptTouchEvent,看是否拦截。
- 如果触摸事件被拦截,则调用ViewGroup的dispatchTransformedTouchEvent方法,其实是调用View的dispatchTouchEvent方法。否则继续向下。
当触摸事件为MotionEvent.ACTION_DOWN时,首先获取根据绘制顺序保存了所有子View的ArrayLsit,然后再根据视图顺序去遍历子View。
- 如果从TouchTarget形成的链表中发现该View,则跳出循环,即找到了TouchTarget。否则继续向下。
- 在子View中寻找,当子View的dispatchTouchEvent方法返回为true时,则找到了新的TouchTarget,并将其添加到TouchTarget形成的链表中。
- 遍历TouchTarget形成的链表,然后对链表里面的子View分别调用dispatchTouchEvent,最后将处理结果返回。
相关推荐
瓜牛呱呱 2020-11-12
柳木木的IT 2020-11-04
yifouhu 2020-11-02
lei0 2020-11-02
源码zanqunet 2020-10-28
源码zanqunet 2020-10-26
一叶梧桐 2020-10-14
码代码的陈同学 2020-10-14
lukezhong 2020-10-14
lzzyok 2020-10-10
anchongnanzi 2020-09-21
clh0 2020-09-18
changcongying 2020-09-17
星辰大海的路上 2020-09-13
abfdada 2020-08-26
mzy000 2020-08-24
shenlanse 2020-08-18
zhujiangtaotaise 2020-08-18
xiemanR 2020-08-17