一点见解: Android事件分发机制(一) - 基本概念解释
一点见解: Android事件分发机制(二) - 分析ViewGroup
一点见解: Android事件分发机制(三) - 分析View
本文是整个事件分发机制分析系列的第一篇, 主要目的是解释事件分发机制当中涉及的组件和概念.
意义
事件分发机制解决的问题是在Android视图组件间传递用户在设备屏幕上的操作, 例如点击, 滑动等.
任何操作都离不开事件分发机制, 了解事件分发机制可以更好地实现复杂的交互操作和更好地分析特殊操作源码.
事件(MotionEvent)
虽然分发机制的目的是传递用户在屏幕上的操作, 但是Android不会直接传递一整个操作
系统会把用户的操作分解成一系列的事件, 然后逐个传递这些事件. 事件可以看作是用户操作过程的节点, 每次分发只会分发一个事件.
例如一个滑动操作一般划分为: 手指接触屏幕 --> 移动手指(多个) --> 手指离开屏幕. Android事件分发机制所传递的就是这些分解之后的事件(手指接触屏幕, 移动手指, 手指离开屏幕).
Android里代表这些事件的是MotionEvent
类, 在大部分事件分发机制中涉及的方法里面都包含一个MotionEvent
实例, 例如View.OnTouchListener#onTouch(View v, MotionEvent event)
. 这个实例包含了当前传递的事件的所有信息, 最常用到的是事件的触点位置(就是手指的位置)和事件类型.
其中最重要的就是事件类型了, 就是打开源码就能看到的各种ACTION_XXX
, 所以之后都会用ACTION_XXX
来表示一个事件.
其中在事件分发机制里面最常出现的有
-
ACTION_DOWN
: 代表手指首次接触屏幕, 所有的操作的第一步都是接触屏幕, 所以事件分发的第一个事件总是ACTION_DOWN
. -
ACTION_MOVE
: 代表手指在屏幕上移动, 是一个操作的中间状态, 是区分不同操作的关键, 也是视图控件主要关注的事件类型, 因为就是靠ACTION_MOVE
来区分一个操作是点击还是滑动. -
ACTION_UP
: 代表手指离开屏幕, 所有操作的最后一步都是离开屏幕, 所以事件序列里面最后一个事件分发的总是ACTION_UP
. -
ACTION_CANCEL
: 代表事件传递被中断, 因为事件分发还存在消费的概念, 这是后面需要解释的, 所以会出现事件传递不完整的情况, 需要通过ACTION_CANCEL
来通知控件, 后面的事件没你份了. -
ACTION_POINTER_UP
和ACTION_POINTER_DOWN
: 代表有另一个手指接触/离开屏幕, 用来处理多点触控的情况.
注意, 传递事件和接收事件是有区别的, 这里说的传递是指系统传递给app的事件, 但是对于控件来说, 它不一定能接收到所有事件, 也就是说对控件来说它接收到的第一个事件不一定是ACTION_DOWN
, 最后一个事件也不一定是ACTION_UP
/ACTION_CANCEL
.
事件是通过控件一层层往下传递的, 对控件来说, 它能接收到什么事件是由上一级控件决定的.
消费(Consume)
消费是指某个事件被某个控件"消耗"掉了.
事件被消费代表着这个事件(不是整个操作)不应该继续传递给下一个控件了.
在分发机制涉及的方法里面很多方法的返回值都是boolean
类型, 例如View.OnTouchListener#onTouch(View v, MotionEvent event)
. 这个值就是标记该事件是否被消费了.
分发对象
事件分发机制的目的是在控件间传递事件, 那么分发的对象自然是控件了.
控件即是分发者也是分发对象.
所以最基本的分发机制逻辑就包含在控件的基类当中. 所以分析事件分发机制的关键就是分析两大控件的相关代码实现, View
和ViewGroup
.
值得指出的是, ViewGroup
也是继承自View
, 所以需要注意它们的具体实现的差别.