Android开发中的事件分发机制梳理
事件分发机制是一块Android比较重要的知识体系,了解并熟悉整套的分发机制有助于更好的分析各种点击滑动失效问题,更好去扩展控件的事件功能和开发自定义控件
Android 事件分发流
仔细看的话,图分为3层,从上往下依次是Activity、ViewGroup、View

箭头的上面字代表方法返回值,(return true、return false、return super.xxxxx(),super 的意思是调用父类实现。
dispatchTouchEvent和 onTouchEvent的框里有个【true---->消费】的字,表示的意思是如果方法返回true,那么代表事件就此消费,不会继续往别的地方传了,事件终止。
目前所有的图的事件是针对ACTION_DOWN的,对于ACTION_MOVE和ACTION_UP我们最后做分析
如果事件不被中断,整个事件流向是一个类U型图

整个事件流向应该是从Activity---->ViewGroup--->View 从上往下调用dispatchTouchEvent方法,一直到叶子节点(View)的时候,再由View--->ViewGroup--->Activity从下往上调用onTouchEvent方法。
dispatchTouchEvent 和 onTouchEvent 一旦return true,事件就停止传递了(到达终点)(没有谁能再收到这个事件)
对于return true我们经常说事件被消费了,消费了的意思就是事件走到这里就是终点,不会往下传,没有谁能再收到这个事件了

dispatchTouchEvent 和 onTouchEvent return false的时候事件都回传给父控件的onTouchEvent处理

对于dispatchTouchEvent 返回 false 的含义应该是:事件停止往子View传递和分发同时开始往父控件回溯(父控件的onTouchEvent开始从下往上回传直到某个onTouchEvent return true),事件分发机制就像递归
对于onTouchEvent return false 就比较简单了,它就是不消费事件,并让事件继续往父控件的方向从下往上流动
dispatchTouchEvent、onTouchEvent、onInterceptTouchEvent ViewGroup 和View的这些方法的默认实现就是会让整个事件安装U型完整走完,所以 return super.xxxxxx() 就会让事件依照U型的方向的完整走完整个事件流动路径),中间不做任何改动,不回溯、不终止,每个环节都走到。

onInterceptTouchEvent 的作用

Intercept 的意思就拦截,每个ViewGroup每次在做分发的时候,问一问拦截器要不要拦截(也就是问问自己这个事件要不要自己来处理)
如果要自己处理那就在onInterceptTouchEvent方法中 return true就会交给自己的onTouchEvent的处理,如果不拦截就是继续往子控件往
下传。默认是不会去拦截的,因为子View也需要这个事件,所以onInterceptTouchEvent拦截器return super.onInterceptTouchEvent()和
return false是一样的,是不会拦截的,事件会继续往子View的dispatchTouchEvent传递
ViewGroup 和View 的dispatchTouchEvent方法返回super.dispatchTouchEvent()的时候事件流走向。

过Interceptor把事件拦截下来给自己的onTouchEvent,所以ViewGroup dispatchTouchEvent方法的super默认实现就是去调用onInterceptTouchEvent
关于ACTION_MOVE 和 ACTION_UP
ACTION_MOVE和ACTION_UP在传递的过程中并不是和ACTION_DOWN 一样
ViewGroup1 的dispatchTouchEvent 方法返回true消费这次事件
红色的箭头代码ACTION_DOWN 事件的流向
//打印日志
Activity | dispatchTouchEvent --> ACTION_DOWN
ViewGroup1 | dispatchTouchEvent --> ACTION_DOWN
---->消费

Activity | dispatchTouchEvent --> ACTION_MOVE
ViewGroup1 |dispatchTouchEvent --> ACTION_MOVE
----
TouchEventActivity | dispatchTouchEvent --> ACTION_UP
ViewGroup1 |dispatchTouchEvent --> ACTION_UP
----
我们在ViewGroup2 的dispatchTouchEvent 返回true消费这次事件
Activity | dispatchTouchEvent --> ACTION_DOWN
ViewGroup1 | dispatchTouchEvent --> ACTION_DOWN
ViewGroup1 | onInterceptTouchEvent --> ACTION_DOWN
ViewGroup2 | dispatchTouchEvent --> ACTION_DOWN
---->消费
Activity | dispatchTouchEvent --> ACTION_MOVE
ViewGroup1 | dispatchTouchEvent --> ACTION_MOVE
ViewGroup1 | onInterceptTouchEvent --> ACTION_MOVE
ViewGroup2 | dispatchTouchEvent --> ACTION_MOVE
----
TouchEventActivity | dispatchTouchEvent --> ACTION_UP
ViewGroup1 | dispatchTouchEvent --> ACTION_UP
ViewGroup1 | onInterceptTouchEvent --> ACTION_UP
ViewGroup2 | dispatchTouchEvent --> ACTION_UP
----

得出结论如果在某个控件的dispatchTouchEvent 返回true消费终结事件,
那么收到ACTION_DOWN 的函数也能收到 ACTION_MOVE和ACTION_UP。
View 的onTouchEvent 返回true消费这次事件

ViewGroup 2 的onTouchEvent 返回true消费这次事件

ViewGroup 1 的onTouchEvent 返回true消费这次事件

View的dispatchTouchEvent 返回false并且Activity 的onTouchEvent 返回true消费这次事件

ViewGroup2的dispatchTouchEvent 返回false并且在ViewGroup1 的onTouchEvent返回true消费这次事件


网友评论