如果要一句话简单总结的话,就是:
找到一个按照规则“消耗”掉MotionEvent.ACTION_DOWN事件的View,默认情况下,后继会把整个事件流都交给它来处理。
#.总体概括
Android手机是可触屏的设备,其它Android设备一般也是可触屏的。可触屏设备允许用户与屏幕进行一些触碰的互动,系统识别各式各样的触摸操作,然后做出复杂的功能反应。本文一切都是针对Android手机来分析说明的。
用户手机触摸屏幕的那一瞬间,Android系统就会把这一次的触屏操作相关信息封装成一个MotionEvent对象,用来描述本次触屏操作,包括触屏操作的类型、发生的时刻、对应的位置坐标等。每一轮触屏操作,总是以手指按下屏幕开始(ACTION_DOWN),手指在屏幕上可以进行各种轨迹的滑动(ACTION_MOVE),然后手指松开屏幕结束这一轮触屏操作(ACTION_UP)。在这个过程中,每一次系统识别到了新的触屏操作(按下/滑动/松开),都会封装对应的MotionEvent对象,这一轮的所有事件叫做一个“事件流”。“事流”这个概念在分析事件具体分发的时候会用到。(当然,每个人的叫法不同。)
一个事件流中的事件,会按照View树的结构,分析判断并最终传递给指定的View目标来处理,或者最终没有任何目标View处理,最终交给Activity、Dialog这种最顶层的组件来处理。正常情况下,一个“事件流”只会交给一个目标View来处理,谁消耗了整个事件流的起始事件——按下事件(MotionEvent.ACTION_DOWN),谁就是目标View,后面整个事件流的所有事件都会逐层传递给它来处理。(之所以说正常情况,是因为开发者可以干预这个过程,通过继承并修改事件传递和拦截的方法,可以在原目标View的更上层ViewGroup拦截事件,将事件流的后继事件交给更上层ViewGroup来处理。)“按下”(MotionEvent.ACTION_DOWN)事件非常关键,它决定了谁是整个事件流的目标View。MotionEvent.ACTION_DOWN事件的整个分发过程是按照“责任链模式”来设计的,按照View树结构,从顶层开始先向下一层一层的链式分发,一直分发到View树叶子节点这一层 或者 中间某一层ViewGroup拦截了事件,然后从这一层开始从下往上回溯,回溯的过程中每一层ViewGroup会判断下层子View是否“完成了责任"(即消耗了事件),没消耗的话自己回去尝试“完成责任”,最后通过返回值告诉自己的上一层View:自己这个View树分支是否“完成了责任”。上一层View又会重复这个过程,周而复始,若是没有任何一层来“完成责任”,最后会交给Activity、Dialog这些最顶层的组件来处理。
#.MotionEvent介绍
Android将所有触屏手势事件都封装在了MotionEvent对象中。
1.每种事件有其对应的类型,常见的事件类型有:
MotionEvent.ACTION_DOWN // 第一个触点被按下时触发(因为可能有多个手指去按屏幕)MotionEvent. ACTION_MOVE // 有触点移动时触发MotionEvent. ACTION_UP // 最后一个触点放开时触发MotionEvent.ACTION_CANCEL //当前事件流被取消,该类型事件不是由用户操作触发的,而是分发处理逻辑在一定场景下触发的。一般触发场景是:某一个View消耗了MotionEvent.ACTION_DOWN成为该事件流的目标View,但后面按照开发者写的特定拦截逻辑,在上层某个ViewGroup拦截了事件流中的后继事件,那么这时候会触发一次 MotionEvent.ACTION_CANCEL事件,传递给原来的目标View。