《Android 开发艺术探索》第 3 章 142 页中使用了一个通俗易懂的例子一语道破了事件分发机制的“天机”。
假如点击事件是一个难题,这个难题最终被上级领导分给了一个程序员去处理(这是事件分发过程),结果这个程序员搞不定(onTouchEvent 返回了 false),现在该怎么办呢?
难题必须要解决,那只能交给水平更高的上级解决(上级的 onTouchEvent 被调用),如果上级再搞不定,那只能交给上级的上级去解决,就这样将难题一层层地向上抛,这是公司内部一种很常见的处理问题的过程。
不 设 按 键 监 听 点 击 分 发 不设按键监听点击分发 不设按键监听点击分发
▼ ▼ ▼
1. 不设置按键监听,在红色区域点击一下,顺序说出调用了哪个控件的哪个事件分发相关方法?
这个问题比较简单,无需赘述,答案如下(首行缩进关系表示当前方法在上一步方法内部调用):
① 调用 FrameLayout 的 dispatchTouchEvent,即对应 ViewGroup 中的 dispatchTouchEvent 方法。
② 调用 FrameLayout 的 onInterceptTouchEvent。因为没有重写事件拦截,所以返回默认 false。
③ 调用 TextView 的 dispatchTouchEvent,即对应 View 中的 dispatchTouchEvent 方法。
④ 调用 TextView 的 onTouchEvent。因为 onInterceptTouchEvent 只有 ViewGroup 有,TextView 不是 ViewGroup,也就不存在事件拦截方法。因为未设置相关按键监听消费事件,所以返回默认 false。
⑤ 调用 FrameLayout 的 super.dispatchTouchEvent,即对应 View 中的 dispatchTouchEvent 方法。因为子控件 TextView 没有消费事件,转由 FrameLayout 尝试消费事件。
⑥ 调用 FrameLayout 的 onTouchEvent。因为未设置相关按键监听消费事件,所以返回默认 false。
相信这个问题难不倒大部分同学。但是,问题结束了吗?
众所周知,普通点击事件包含 DOWN 事件和 UP 事件,上面说的只是 DOWN 事件,UP 事件呢?
1.1 因为 DOWN 事件无人消费,那么 UP 事件是否还能分发到 FrameLayout?
如果不能,那 UP 事件去哪了?
这个问题其实我刚开始自问自答时,也没有回答上来。
在回答这个问题前,有必要科普一下 Android 开发者文档中描述的事件流一致性保证(Consistency Guarantees):
按下开始,中间可能伴随着移动,直到松开或者取消结束。
DOWN → MOVE(*) → UP/CANCEL。
简单来说,一条事件流就像一辆火车,车头和车尾是必须要有的,中间的车厢可有可无,有的话可以是任意节。DOWN 事件相当于火车头,UP 或 CANCEL 相当于火车尾,MOVE 事件相当于火车厢。我们