如上图所示,这是事件ACTION_DOWN
的流程图,而ACTION_MOVE
和ACTION_UP
则是根据ACTION_DOWN
的消费来定。
- 如果
ViewGroupA
和View
都没有对ACTION_DOWN
事件进行消费,则ACTION_MOVE
的流程就是Activity.dispatch
->Activity.onTouch
- 如果
View
的onTouch
返回了true
,对ACTION_DOWN
进行了消费,则ACTION_MOVE
的流程是Activity.dispath
->ViewGroupA.dispatch
->ViewGroupA.onIntercept
->View.dispatch
->View.onTouch
下面分析一下源码:
activity_dispatchTouchEvent.png-
如
MainActivity
继承Activity
且重写dispatchTouchEvent
,不调用super.dispatchTouchEvent
,则事件不再继续. -
当点击事件触发,先调用Activity中的
dispatchTouchEvent
方法,然后调用的getWindow().superDispatchTouchEvent(ev)
,再看if条件,如果getWindow().superDispatchTouchEvent(ev)
返回true,则直接return,如果返回false才走onTouchEvent
. -
看看
getWindow().superDispatchTouchEvent(ev)
,这边直接调用了Window
的superDispatchTouchEvent
,Window
是一个虚类,所以该方法在子类中实现,根据Window
类上面的注释The only existing implementation of this abstract class is android.view.PhoneWindow,找到PhoneWindow
.
,再看mDecor
,
注释也得很清楚了,top-level view of the window.并且从代码中可以知道,DecorView
继承了FragmeLayout
,FrameLayout
继承自ViewGroup
.
所以调用了ViewGroup
的dispatchTouchEvent
方法.
- 那来看看
ViewGroup
的dispatchTouchEvent
方法,一看源码,好长一段,一步步看吧.
这个标着红色的,不在ViewGroup
里面,因为ViewGroup
继承View
,就去View中了下
看不懂只能看注释了,注释还是写的很清楚的,用于调试的一致性验证器
,这是用于调试的,跟我们没多大关系,然后接着往下看,
解释一下这堆代码,第一个条件ev.isTargetAccessibilityFocus():是否应该被有焦点的控件先处理
,第二个条件isAccessibilityFocusedViewOrHost():没有焦点, 不处理这个事件
,结果ev.setTargetAccessibilityFocus(false);:目标View已经处理过了来, 接着用正常逻辑分发
,这部分解释是网络上抄来的.继续看源码if (onFilterTouchEventForSecurity(ev))
这个方法有注释,是用来过滤事件以应用安全策略.
直接看一下cancelAndClearTouchTargets
方法,点击看注释Cancels and clears all touch targets.:取消和清除所有触摸目标
,再看resetTouchState
方法,继续看注释Resets all touch state in preparation for a new cycle.:重置所有的触摸状态以准备一个新的周期
,我的理解,Action_Down作为新一轮事件的开始,就摒弃之前触摸事件的状态,重新进入周期.
关于resetTouchState
还得讲一下,方法里面有一个mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
后面需要用到.接着往下看
先看if里面的条件,条件一actionMasked == MotionEvent.ACTION_DOWN
当为Action_down事件的时候,if成立,此时第二个条件mFirstTouchTarget != null
是不成立的,代码在resetTouchState
方法里的clearTouchTargets
,就不多解释了,反过来,第一个条件不成立时,就不会重新清楚状态,上面讲了,只有action_down时,才会清除状态,所以第一个条件不成立时,第二个条件是成立的.那就是不管咋样,if都是成立的,那要else干啥,只能看注释了:没有触摸目标,这个动作不是最初的,因此这个视图组继续拦截触摸
.这就可以理解了.接着看下一个条件final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
上面在clearTouchTargets
中提到mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
,这两个一看就是0.所以disallowIntercept = flase
,下面的if条件成立,进而会调用onInterceptTouchEvent(ev);
拦截方法.
接着往下看:
viewgroup_dispatchTouchEvent_6.PNG在红线标注的这两个地方调用了dispatchTransformedTouchEvent
从源码中看出,当该ViewGroup
的child
为View
的时候,就调用super.dispatchTouchEvent
,如果还是ViewGroup
,则继续调用child.dispatchTouchEvent
网友评论