1. 基础知识
(1) 所有 Touch
事件都被封装成 MotionEvent
对象,包括 Touch的位置、时间、历史记录以及第几个手指(多指触摸)等。
(2) 事件类型分为: ACTION_DOWN
,ACTION_UP
,ACTION_MOVE
,ACTION_POINTER_DOWN
,ACTION_POINTER_UP
,ACTION_CANCEL
,每个事件都是以ACTION_DOWN
开始,ACTION_UP
结束的。
(3) 对事件的处理包括三类:
- 传递——
dispatchTouchEvent()
- 拦截——
onInterceptTouchEvent()
- 消费——
onTouchEvent()
和onTouchListener()
,onTouchListener()
优先于onTouchEvent()
对事件进行消费。
2. 图解Android 事件分发机制
1. Android 事件分发流
注意:
- 仔细看的话,图分为3层,从上往下依次是Activity、ViewGroup、View
- 事件从左上角那个白色箭头开始,由Activity的dispatchTouchEvent做分发
- 箭头的上面字代表方法返回值,(return true、return false、return super.xxxxx()),super 的意思是调用父类实现。
dispatchTouchEvent
和onTouchEvent
的框里有个【true—->消费】的字,表示的意思是如果方法返回true,那么代表事件就此消费,不会继续往别的地方传了,事件终止。- Activity 的
dispatchTouchEvent
无论返回什么,都会调用ViewGroup 的dispatchTouchEvent
(自行看源码)
2. 详细分析
1. 如果事件不被中断,整个事件流向是一个类U型图
所以如果我们没有对控件里面的方法进行重写或更改返回值,而直接用super调用父类的默认实现,那么整个事件流向应该是从Activity—->ViewGroup—>View 从上往下调用dispatchTouchEvent方法,一直到叶子节点(View)的时候,再由View—>ViewGroup—>Activity从下往上调用onTouchEvent方法。
2. dispatchTouchEvent
和 onTouchEvent
一旦return true
,事件就停止传递了(到达终点)(没有谁能再收到这个事件)
看下图中只要return true事件就没再继续传下去了,对于return true我们经常说事件被消费了,消费了的意思就是事件走到这里就是终点,不会往下传,没有谁能再收到这个事件了。
3. dispatchTouchEvent
和 onTouchEvent
return false
的时候事件都回传给父控件的onTouchEvent
处理。
看上图深蓝色的线,对于返回false的情况,事件都是传给父控件onTouchEvent处理。
- 对于dispatchTouchEvent return false 的含义应该是:事件停止往子View传递和分发同时开始往父控件回溯(父控件的onTouchEvent开始从下往上回传直到某个onTouchEvent return true),事件分发机制就像递归,return false 的意义就是递归停止然后开始回溯。
- 对于onTouchEvent return false 就比较简单了,它就是不消费事件,并让事件继续往父控件的方向从下往上流动。
4. onInterceptTouchEvent
的作用
Intercept
的意思就拦截,每个ViewGroup
每次在做分发的时候,问一问拦截器要不要拦截(也就是问问自己这个事件要不要自己来处理)
- 如果要自己处理那就在
onInterceptTouchEvent()
方法中 return true 就会交给自己的onTouchEvent()
的处理 - 如果不拦截就是继续往子控件往下传。默认是不会去拦截的,因为子View也需要这个事件,所以
onInterceptTouchEvent()
拦截器return super.onInterceptTouchEvent()
和return false
是一样的,是不会拦截的,事件会继续往子View的dispatchTouchEvent()
传递。
5. ViewGroup 和View 的dispatchTouchEvent方法返回super.dispatchTouchEvent()的时候事件流走向。
ViewGroup 的dispatchTouchEvent():,
- return true 是终结传递。
- return false 是回溯到父View的
onTouchEvent()
- ViewGroup 通过 super() 方法调用
onInterceptTouchEvent()
,从而把事件拦截下来给自己的onTouchEvent()
View 的 dispatchTouchEvent()
- return true 是终结
- return false 是回溯会父类的
onTouchEvent()
- return super.dispatchTouchEvent(),View类的
dispatchTouchEvent()
方法默认实现就是能帮你调用View自己的onTouchEvent()
方法的。
总结一下:
- 对于
dispatchTouchEvent()
,onTouchEvent()
,return true
是终结事件传递。return false
是回溯到父View的onTouchEvent()
方法。 - ViewGroup 想把自己分发给自己的
onTouchEvent()
,需要拦截器onInterceptTouchEvent()
方法return true
把事件拦截下来。 - ViewGroup 的拦截器
onInterceptTouchEvent()
默认是不拦截的,所以return super.onInterceptTouchEvent()=return false
; - View 没有拦截器,为了让View可以把事件分发给自己的
onTouchEvent()
,View的dispatchTouchEvent()
默认实现(super)就是把事件分发给自己的onTouchEvent()
。
3. ACTION_DOWN 事件传递总结
ViewGroup和View 的dispatchTouchEvent 是做事件分发,那么这个事件可能分发出去的四个目标
注:——> 后面代表事件目标需要怎么做。
- 自己消费,终结传递。——->return true ;
- 给自己的onTouchEvent处理——-> 调用super.dispatchTouchEvent()系统默认会去调用 onInterceptTouchEvent,在onInterceptTouchEvent return true就会去把事件分给自己的onTouchEvent处理。
- 传给子View——>调用super.dispatchTouchEvent()默认实现会去调用 onInterceptTouchEvent 在onInterceptTouchEvent return false,就会把事件传给子类。
不传给子View,事件终止往下传递,事件开始回溯,从父View的onTouchEvent开始事件从下到上回归执行每个控件的onTouchEvent——->return false;
注: 由于View没有子View所以不需要onInterceptTouchEvent 来控件是否把事件传递给子View还是拦截,所以View的事件分发调用super.dispatchTouchEvent()的时候默认把事件传给自己的onTouchEvent处理(相当于拦截),对比ViewGroup的dispatchTouchEvent 事件分发,View的事件分发没有上面提到的4个目标的第3点。
ViewGroup和View的onTouchEvent方法是做事件处理的,那么这个事件只能有两个处理方式:
- 自己消费掉,事件终结,不再传给谁—–>return true;
- 继续从下往上传,不消费事件,让父View也能收到到这个事件—–>return false;View的默认实现是不消费的。所以super==false。
ViewGroup的onInterceptTouchEvent方法对于事件有两种情况:
- 拦截下来,给自己的onTouchEvent处理—>return true;
- 不拦截,把事件往下传给子View—->return false,ViewGroup默认是不拦截的,所以super==false;
4. 关于 ACTION_MOVE 和 ACTION_UP
- 简单的说,就是当
dispatchTouchEvent()
在进行事件分发的时候,只有前一个事件(如ACTION_DOWN)返回true,才会收到ACTION_MOVE和ACTION_UP的事件。 - 如果在某个控件的dispatchTouchEvent() 返回true消费终结事件,那么收到ACTION_DOWN 的dispatchTouchEvent()函数也能收到 ACTION_MOVE和ACTION_UP。
- 对于在onTouchEvent消费事件的情况:在哪个View的onTouchEvent 返回true,那么ACTION_MOVE和ACTION_UP的事件从上往下传到这个View后就不再往下传递了,而直接传给自己的onTouchEvent 并结束本次事件传递过程。
[参考文献]