这里接着上一篇:Android事件分发机制的源码分析(一)-Activity篇 - 简书
ViewGroup 的事件分发
通过上一篇,我们得知:getWindow().superDispatchTouchEvent(ev) 最后会传到
VIewGroup的dispatchTouchEvent()。
小结:
cancelAndClearTouchTargets(ev):mFirstTouchTarget的值代表上一次的点击事件状态,mFirstTouchTarget=null则什么也不做;如果有,将mFirstTouchTarget的值用 TouchTarget全接收并执行 target.recycler()回收掉,最后重置为 null。
resetTouchState(); 将 mGroupFlags 标志位进行了一个清除操作。
接着往下看:
根据源码注释:intercepted = true时,对事件进行拦截,不分发;默认是false的,也就是不拦截事件,向下继续分发。
disallowIntercept这里计算是得出 false值,这是因为上面的 cancelAndClearTouchTargets()与resetTouchState()中,mGroupFlags 和FLAG_DISALLOW_INTERCEPT 被初始化了。但是可以通过调用 requestDisallowInterceptTouchEvent()改变 (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0的值。
接着看 onInterceptTouchEvent()。
总结:onInterceptTouchEvent()默认false,表示不拦截事件;true代表 ViewGroup要拦截这个事件,那么同一事件的序列将不会在调用此方法。
补充:
MotionEvent.ACTION_POINTER_DOWN :屏幕有多个手指按下,触发。
MotionEvent.ACTION_HOVER_MOVE :鼠标在窗口或者View区域移动,但没有按下。
canViewReceivePointerEvents():表示能否接收点击事件,如果 view可见或动画执行完毕,就返回 true。
isTransformedTouchPoinInView():表示触摸产生的区域是否在 View的范围之内。
然后,我们接着看 dispatchTransformedTouchEvent()里面是什么。
情况1: child == null,会调用 view的dispatchTouchEvent(event),这方法到底干了什么,第三篇再讲。
情况2:child!=null,会调用 child.dispatchTouchEvent(transformedEvent)把事件分发下去,最后回收 Motion事件。
接着,展开 dispatchTransformedTouchEvent();
addTouchTarget():对 mFirstTouchTarget = 子View,然后把 alreadyDispatchedToNewTouchTarget设置 true,意思是说:子 View消费了事件,mFirstTouchTarget就指向子 View。
另外:子View的onTouchEventf()为false,即不消费事件;那么 dispatchTransformedTouchEvent()就变为 false,就不会执行 addTouchTarget(),也就是说mFirstTouchTarget = null,这也是为什么 子View为什么不可以继续处理 ACTION_MOVE事件 和ACTION_UP事件。
小结:这块代码就是对 ACTION_DWON根据不同情况不同处理。
true:事件被消费,mFirstTouchTarget不为null
false:事件未被消费,mFirstTouchTarget为null
接着往下看
mFirstTouchTarget == null时,dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS),当第三个值 为null传进去,代表 child为null表示没有子View。child ==null时,handle = super.dispatchTouchEvent(event)也就是当前 viewGroup会执行 onTouch事件。
mFirstTouchTarget != null时,然后就会进入if( alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {},在之前的分析,这俩值都会是true。然后继续判断有无子 View消费。有的话 handler就会返回true,如果返回false,后面就是通过指针赋值,把后面的 MOVE和UP事件进行处理。
最后总结:
Android事件分发,是 Activity → ViewGroup → View 。ViewGroup可以通过 onInterceptTouchEvent()进行拦截(默认不拦截),拦截了之后 MOVE、UP不会在调用 onInterceptTouchEvent()。因为 ViewGroup拦截后,mFirstTouchTarget 一直为 null(找不到消费的子VIew)
那么,if(actionMasked == MotionEvent.ACTION_DWON || mFirstTouchTarget != null) 就一直是false,不会进入到里面执行 onTenterceptTouchEvent()。而我们的子View 是无法通过 getParent(). requestDisallowInterceptTouchEvent ()方法来拦截我们的ViewGroup的DOWN事件的,因为DOWN事件每次都会对 FLAG_DISALLOW_INTERCEPT 和 mGroupFlags 进行重置,还是会进入到if中 重新计算intercepted得到值依然是flase。但是可以调用getParent(). requestDisallowInterceptTouchEvent () 来禁止或者允许 我们的 ViewGroup 是否拦截我们的 MOVE 和 UP 事件。如果子类中,Touch事件被消费了,那么ViewGroup 就不会对Touch事件再进行处理。
最后,ViewGroup 的 dispatchTouchEvent() 是分发,而 View的 dispatchTouchEvent()是分发给自己,处理的方法是 OnTouchEvent ()。而ViewGroup是没有重写 onTouchEvent()。
网友评论