一、ViewRoot 和 DecorView
ViewRoot 对应于 ViewRootImpl,是连接 WindowManager 和 DecorView 的纽带,View 的三大流程都是通过 ViewRoot 来完成的。在 Activity 初始化的时候就会将 DecorView 添加到 Window 中,同时创建 ViewRootImpl 对象,并建立 ViewRootImpl 对象和 DecorView 之间的联系。DecorView 其实就是一个 FrameLayout ,所有事件都要先经过 DecorView 才能传递给我们的 View。
二、事件分发机制
Touch 事件通过底层接收,传递到 ViewRootImpl 中,然后分发给 DecorView,首先回调给 Activity 的 dispatchTouchEvent 处理,然后回到 DecorView 开始往子 View 进行 Dispatch.
在 TouchEvent dispatchTouchEvent 到某 ViewGroup 中时,会有三步判断,如上图浅绿色所示。
dispatchTouchEvent
(分发的方法,可以决定是否屏蔽onInterceptTouchEvent方法)->onInterceptTouchEvent
(是否拦截)->onTouchEvent
1. disallowIntercept?
在 onInterceptTouchEvent 方法之前还有一个是否屏蔽 onInterceptTouchEvent 的方法,那就是 disallowIntercept。
ViewGroup 有一个 disallowIntercept 开关,可以设置此 ViewGroup 是否屏蔽onInterceptTouchEvent 事件,如果开启此开关,则此 ViewGroup 跳过自身的 onInterceptTouchEvent 事件,直接 dispatchTouchEvent 到子 View。
另外,每次 ACTION_DOWN 的时候,disallowIntercept 会被重置,默认为允许调用onInterceptTouchEvent
requestDisallowInterceptTouchEvent(true)
这个就会让自己这个布局屏蔽掉onInterceptTouchEvent 事件,同样,我们也能在子控件里面调用getParent().requestDisallowInterceptTouchEvent(true)
来让父布局屏蔽掉onInterceptTouchEvent 事件。
2. intercept?
onInterceptTouchEvent 返回值为 true
当调用 ViewGroup 的 onInterceptTouchEvent 后返回值为 true,则表示当前 ViewGroup 拦截了此 TouchEvent 事件,此 ViewGroup 的 onTouchEvent 会收到回调;onInterceptTouchEvent 返回值为 false
如果返回值为 false,则调用 dispatchTransformedTouchEvent,去寻找此 Point 上 hit 到的子 View,如果寻找到子 View,则调用子 View 的 dispatchTouchEvent 事件,否则就调用 super.dispatchTouchEvent,即调用 View 的 dispatchTouchEvent 实现,在此会调用到 onTouchEvent 函数去处理此 TouchEvent 事件。onInterceptTouchEvent 总结
onInterceptTouchEvent流程为父ViewGroup->子ViewGroup->孙ViewGruop
,如果其中一个ViewGroup拦截了事件,则此ViewGroup直接处理OnTouchEvent事件,且TouchEvent不在往下 dispatch,而是开始 return。
3. handled?
onTouchEvent 返回值为true,则此TouchEvent被处理完毕
onTouchEvent 返回值为false,则return给父ViewGroup,父ViewGroup会继续交给此ViewGroup的兄弟View处理,就是一直往上抛,直到有一个View把这个事件消耗掉。
三、责任链模式
Android 的事件分发机制是典型的责任链模式,当用户触摸屏幕的时候,Android 都会将对应的事件包装成一个事件对象,从 ViewTree 的顶部至上而下的分发传递。主要代码逻辑可以去看 ViewGroup 的 dispatchTouchEvent 方法。
ViewGroup 事件投递的递归调用就类似于一条责任链,一旦其寻找到责任者,那么将由责任者持有并消费掉该次事件,具体地体现在 View 的 onTouchEvent 方法中的返回值,false 代表当前 View 不是该次事件的负责人,true 代表当前 View 是该次事件的责任人,此时 View 就会持有该事件并不再向外传递。