最近工作需要需要做一些比较复杂的自定义 View,其中事件分发的处理自然少不了结合之前阅读过的大量资料,工作是完成了,但是对事件分发的处理总觉得很不清晰,知其然不知其所以然的感觉让人很不舒服。如果不知道事件分发原理,要是处理的情很复杂的话,那就很难解决了。之前也看过任玉刚的《安卓开发艺术探索》对于事件发源码的分析,但只能说大致了解了事件分发的流程,而不知其中的道理。网上关于事件分发的文章也是非常多,但是总感觉没说到原理,即是说了也很让人雾里看花。
索性践行某位大师的名言——
“read the fucking source”
源码的阅读总是让人痛并快乐着,一是因为源码很长逻辑很复杂,二是因为源码要考虑
的东西太多,所以干扰的东西实在太多,经常跟进去就迷路。
介于本文是对源码层次的分析,所以如果大家还没了解过事件分发的基本流程的话,最
好先看一下这方面的资料。
首先,关于事件分发,相信接触过的人都看过类似这样一张 U 型图片:
并且也知道 dispatchTouchEvent、InterceptTouchEvent、onTouchEvent 这三个方
法的作用分别分发事件、拦截事件、消费事件。
也看过类似的伪代码:
其实如果熟悉这些,简单的事件分发已经可以处理了,但是这些只是单纯记忆流程,并
不知道具体的事件在源码中何去何从。
总的来说,ViewGroup 和 View 属于树的结构,事件分发就是从父节点到子节点一步
步遍历的过程,直到找到可以消费事件的 View 为止。而在这一过程中,就是一个不断
递归调用以上伪代码的过程。子 View 总是在经过 dispatchTouchEvent 的执行后将
返回值交给父 View,父 View 根据子 View 是否消费了事件再确定自己是否需要消费
事件,然后再向自己的父 View 返回一个表示自己或者自己的子 View 是否消费了事件
的布尔值。如果当前 View(ViewGroup)自己或者子 View 不消费就会将事件转给父
View 的 onTouchEvent 方法,所以就会呈现了上面的 U 型图。分析了源码之后,更
能体会这其中设计的精妙
关于事件分发源码我认为最好还是模拟一个事件流,跟着代码走,努力避开各种其他代
码的干扰(例如安全检查等),并且从最简单的事件入手,即单指触模、控件不进行滑
动、先不考虑 ACTION_CANCEL 事件。
本文基于 Android23 的源码进行分析。请对照 View 和 ViewGroup 的源码来看本文
首先要明确一个事件序列指的是从手指按下、滑动、抬起的这一个过程中的多个事件。
分别是 DOWN、MOVE、UP 事件。
在这里,假设一个情景,有一个 Activity,里面的布局是最外层一个 ViewGroup A(充
满屏幕),A 里面有个 ViewGroup B(充满 A),B 里面有个 Button C(比如在屏幕
中间)。
情形 1:
A完全(即A上的所有点都要拦截)拦截事件(即InterceptTouchEvent直接返回true),
现在单指点击了一下 A 范围任意点,然后滑动并抬起。
(Activity、PhoneWindow 、DecorView 的分发就不进行分析了)
现在的事件为 ACTION_DOWN。
首先 DecorView 调用了 ViewGroup A 的 dispatchTouchEvent 方法(当然这里只挑
关键代码),看到 ViewGroup 的 2103 行:
这一段很简单,但是很重要。关键在 intercepted = onInterceptTouchEvent(ev);,
大家也很熟悉,此时 A 要拦截事件的,所以 intercepted 为 true。
于是,2134 行的:
登录 | 立即注册