Android 事件分发,你真的了解吗?
android中的事件分发,可以说是面试经常被提及,日常开发中也偶尔会遇到一些事件冲突,弄清楚整个事件分发的流程,是一个基本功,作为搬砖的码农,基础还是要打牢固。
其实网上关于事件分发的文章已经很多了,但是自己总结一下,印象总会深刻一点。
推荐一篇觉得介绍很详细的博文:安卓自定义View进阶-事件分发机制原理
先介绍一下事件分发相关方法,X
表示不含有该方法:
Touch事件相关方法 | 方法功能 | ViewGroup | View | Activity |
---|---|---|---|---|
boolean dispatchTouchEvent (MotionEvent ev) | 事件分发 | √ | √ | √ |
boolean onInterceptTouchEvent (MotionEvent ev) | 事件拦截 | √ | X |
X |
boolean onTouchEvent (MotionEvent ev) | 事件响应 | √ | √ | √ |
首先来一张图:
如果觉得图看完后,还是觉得有点不理解,再看下面的文字总结
1. dispatchTouchEvent
dispatchTouchEvent处理事件分发,且事件分发本身也具有消费能力。
dispatchTouchEvent返回值 | 含义 |
---|---|
true | 表示该事件再本层不再进行分发,且事件已经在分发自身中被消费来,至此,该事件已经完结 |
false | 表示该事件在本层不再继续进行分发,并交由上层控件的onTouchEvent方法去消费(其实是先交给来上层控件的dispatchTouchEvent方法,然后dispatchTouchEvent再调用了自身的onTouchEvent) |
super.dispatchTouchEvent(ev) | 事件将会分发给本层的事件拦截onInterceptTouchEvent方法进行处理 |
2. onInterceptTouchEvent
onInterceptTouchEvent处理事件拦截
onInterceptTouchEvent返回值 | 含义 |
---|---|
true | 表示将事件拦截,并交由本层的控件的onTouchEvent处理 |
false | 表示不拦截,事件将分发到子View,并交由子View的dispatchTouchEvent方法进行处理 |
super.onInterceptTouchEvent(ev) | 事件默认不会被拦截,并交由子View的dispatchTouchEvent方法进行处理 |
3. onTouchEvent
onTouchEvent处理事件消费
onTouchEvent返回值 | 含义 |
---|---|
true | 表示消费了此事件,此时事件终结,将不会继续将事件向上层回传 |
false | 表示未消费事件,将事件继续向上层控件回传,且由上层View的onTouchEvent处理 |
super.onTouchEvent(ev) | 效果同false,表示未消费事件,将事件继续向上层控件回传,且由上层View的onTouchEvent处理 |
注意点1:dispatchTouchEvent的记忆功能
若子View的onTouchEvent放回false,则表示没有消费该事件,交由上层ViewGroup的onTouchEvent处理,然后改次的后续事件 MOVE 、UP 都直接交由上层ViewGroup的onTouchEvent处理。可以理解成下层员工第一件事件就说搞不定,需要上层领导来处理,那么上层领导后续就不会把该次的其他后续事件交给员工了,直接自己处理。
如下表所示,从上到下依次进行,假设事件都能正常向下传递
控件 | 事件分发相关方法 | 当前的事件名称 |
---|---|---|
ViewGroup | dispatchTouchEvent | ACTION_DOWN |
ViewGroup | onInterceptTouchEvent | ACTION_DOWN |
View | dispatchTouchEvent | ACTION_DOWN |
View | onTouchEvent (返回了false) |
ACTION_DOWN |
ViewGroup | onTouchEvent | ACTION_DOWN |
ViewGroup | dispatchTouchEvent | ACTION_MOVE |
ViewGroup | onTouchEvent | ACTION_MOVE |
ViewGroup | dispatchTouchEvent | ACTION_UP |
ViewGroup | onTouchEvent | ACTION_UP |
注意点2:当子View的onTouchEvent返回true时,事件被消费,上层ViewGroup的onTouchEvent不会执行。可以理解成,当下层员工把事件都搞定了,上层leader就不用再去处理该事件了,继续分发下一个事件给员工
注意点3:当ViewGroup的onTouchEvent返回true时,且自身的onInterceptTouchEvent也返回true,则后续的事件ACTION_MOVE、ACTION_UP都不再继续向下层分发,直接交由本层的onTouchEvent处理。可以理解成上级leader在分发任务给下级时,下级没有搞定,然后发现自己能搞定,那么后续的事情就都自己搞定了
如下表所示,从上到下依次进行,
控件 | 事件分发相关方法 | 当前的事件名称 |
---|---|---|
ViewGroup | dispatchTouchEvent | ACTION_DOWN |
ViewGroup | onInterceptTouchEvent(返回了true) |
ACTION_DOWN |
ViewGroup | onTouchEvent (返回了true) |
ACTION_DOWN |
ViewGroup | dispatchTouchEvent | ACTION_MOVE |
ViewGroup | onTouchEvent | ACTION_MOVE |
ViewGroup | dispatchTouchEvent | ACTION_UP |
ViewGroup | onTouchEvent | ACTION_UP |
还由一个相关的方法叫requestDisallowInterceptTouchEvent(true)
, 是告诉父View,不要拦截该事件,父View不再调用onInterceptTouchEvent,直接将事件传递到子View, requestDisallowInterceptTouchEvent(false)
是告诉父View可以对事件进行拦截,具体内容可以自行百度。
后续有时间了,会再写一篇有关滑动事件冲突解决的文章。