在Android开发中,事件分发机制是一块Android比较重要的知识体系,了解并熟悉整套的分发机制有助于更好的分析各种点击滑动失效问题,更好去扩展控件的事件功能和开发自定义控件,同时事件分发机制也是Android面试必问考点之一。总结一句:事件分发机制很重要。
下面先简单介绍一下要分析事件分发机制涉及到的概念:
Android事件分发机制主要处理的对象是:用户对控件(View、ViewGroup)的点击触摸事件
当用户触摸屏幕时(View或ViewGroup派生的控件),将产生点击事件(Touch事件)。
Touch事件相关细节(发生触摸的位置、时间、历史记录、手势动作等)被封装成MotionEvent对象
主要发生的Touch事件有如下四种:
MotionEvent.ACTION_DOWN:按下View(所有事件的开始)
MotionEvent.ACTION_MOVE:滑动View
MotionEvent.ACTION_CANCEL:非人为原因结束本次事件
MotionEvent.ACTION_UP:抬起View(与DOWN对应)
事件列:从手指接触屏幕至手指离开屏幕,这个过程产生的一系列事件,任何事件列都是以DOWN事件开始,UP事件结束,中间有无数的MOVE事件。Android事件分发机制在哪些对象之间传递: Activity、ViewGroup、View
一个点击事件产生后,传递顺序是:Activity(Window) -> ViewGroup -> ViewAndroid事件分发机制的本质:将点击事件(MotionEvent)向某个View进行传递并最终得到处理
即当一个点击事件发生后,系统需要将这个事件传递给一个具体的View去处理。这个事件传递的过程就是分发过程。Android事件分发机制涉及到的方法:dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()
上面简单介绍了事件分发相关的概念和方法,下面就来看一下事件分发的逻辑,下面先附上一张事件分发的示意图
正如上面概念提到的,事件分发的传递顺序是:Activity(Window) -> ViewGroup -> View
- 图分为3层,从上往下依次是Activity、ViewGroup、View
- 事件从左上角那个白色箭头开始,由Activity的dispatchTouchEvent做分发
- 箭头的上面字代表方法返回值,(return true、return false、return super.xxxxx(),super 的意思是调用父类实现。
- dispatchTouchEvent和 onTouchEvent的框里有个【true---->消费】的字,表示的意思是如果方法返回true,那么代表事件就此消费,不会继续往别的地方传了,事件终止。
- 目前所有的图的事件是针对ACTION_DOWN的,对于ACTION_MOVE和ACTION_UP我们最后做分析。
针对上图2,我们可以分析出以下结论:
- 如果事件不被中断,整个事件流向是一个类U型图。
如果我们没有对控件里面的方法进行重写或更改返回值,而直接用super调用父类的默认实现,那么整个事件流向应该是从Activity---->ViewGroup--->View 从上往下调用dispatchTouchEvent方法,一直到叶子节点(View)的时候,再由View--->ViewGroup--->Activity从下往上调用onTouchEvent方法。- dispatchTouchEvent 和 onTouchEvent 一旦return true,事件就停止传递了(到达终点)(没有谁能再收到这个事件)。
看图中只要return true事件就没再继续传下去了,对于return true我们经常说事件被消费了,消费了的意思就是事件走到这里就是终点,不会往下传,没有谁能再收到这个事件了。- dispatchTouchEvent 和 onTouchEvent return false的时候事件都回传给父控件的onTouchEvent处理。
1、对于dispatchTouchEvent 返回 false 的含义应该是:事件停止往子View传递和分发同时开始往父控件回溯(父控件的onTouchEvent开始从下往上回传直到某个onTouchEvent return true),事件分发机制就像递归,return false 的意义就是递归停止然后开始回溯。
2、对于onTouchEvent return false 就比较简单了,它就是不消费事件,并让事件继续往父控件的方向从下往上流动。- onInterceptTouchEvent 的作用(只有ViewGroup中有该方法)
Intercept 的意思就拦截,每个ViewGroup每次在做分发的时候,问一问拦截器要不要拦截(也就是问问自己这个事件要不要自己来处理)如果要自己处理那就在onInterceptTouchEvent方法中 return true就会交给自己的onTouchEvent的处理,如果不拦截就是继续往子控件往下传。默认是不会去拦截的,因为子View也需要这个事件,所以onInterceptTouchEvent拦截器return super.onInterceptTouchEvent()和return false是一样的,是不会拦截的,事件会继续往子View的dispatchTouchEvent传递。- ViewGroup 和View 的dispatchTouchEvent方法返回super.dispatchTouchEvent()的时候事件流走向
1、首先看下ViewGroup 的dispatchTouchEvent,之前说的 return true是终结传递。return false 是回溯到父View的onTouchEvent,然后ViewGroup怎样通过dispatchTouchEvent方法能把事件分发到自己的onTouchEvent处理呢,return true和 false 都不行,那么只能通过Interceptor把事件拦截下来给自己的onTouchEvent,所以ViewGroup dispatchTouchEvent方法的super默认实现就是去调用onInterceptTouchEvent。
2、那么对于View的 dispatchTouchEvent 方法 return super.dispatchTouchEvent()的时候呢事件会传到哪里呢,View中并没有Interceptor,但是同样的道理return true是终结。return false 是回溯会父类的onTouchEvent,怎样把事件分发给自己的onTouchEvent 处理呢,那只能return super.dispatchTouchEvent,View类的dispatchTouchEvent()方法默认实现就是能帮你调用View自己的onTouchEvent方法的。
总结
1、对于 dispatchTouchEvent,onTouchEvent,return true是终结事件传递。return false 是回溯到父View的onTouchEvent方法。
2、ViewGroup 想把自己分发给自己的onTouchEvent,需要拦截器onInterceptTouchEvent方法return true 把事件拦截下来。
3、ViewGroup 的拦截器onInterceptTouchEvent 默认是不拦截的,所以return super.onInterceptTouchEvent()=return false;
4、View 没有拦截器,为了让View可以把事件分发给自己的onTouchEvent,View的dispatchTouchEvent默认实现(super)就是把事件分发给自己的onTouchEvent。
ACTION_MOVE和ACTION_UP
上面的内容都主要是针对ACTION_DOWN的事件传递,而事件序列中还有ACTION_MOVE和ACTION_UP,它们两个的处理就和ACTION_DOWN不同了。ACTION_MOVE和ACTION_UP在传递的过程中并不是和ACTION_DOWN 一样,你在执行ACTION_DOWN的时候返回了false,后面一系列其它的action就不会再得到执行了。简单的说,就是当dispatchTouchEvent在进行事件分发的时候,只有前一个事件(如ACTION_DOWN)返回true,才会收到ACTION_MOVE和ACTION_UP的事件。
总结
ACTION_DOWN事件在哪个控件消费了(return true), 那么ACTION_MOVE和ACTION_UP就会从上往下(通过dispatchTouchEvent)做事件分发往下传,就只会传到这个控件,不会继续往下传,如果ACTION_DOWN事件是在dispatchTouchEvent消费,那么事件到此为止停止传递,如果ACTION_DOWN事件是在onTouchEvent消费的,那么会把ACTION_MOVE或ACTION_UP事件传给该控件的onTouchEvent处理并结束传递。
后续抽空会根据源码再分析一下。 本文主要是自我知识备忘,如有错误,请指正。