Android 学习笔记- View 事件分发机制

Author Avatar
ChihoPang 3月 11, 2018
  • 在其它设备中阅读本文章

关于 View 事件分发机制的学习笔记。

参考资料

《Android 开发艺术探索》第三章

位置参数

Android 视图坐标系

img

View 的位置参数(均以父容器为参考系)

四个原始坐标定点
  • top
  • left
  • right
  • bottom
两个平移偏移量
  • translationX
  • translationY
两个平移后的真实坐标
  • x(left+translationX)
  • y(top+translationY)

MotionEvent 的位置参数

  • getX/getY:相对于当前 View 左上角的 x 坐标和 y 坐标
  • getRawX/getRawY:相对于屏幕左上角的 x 坐标和 y 坐标

事件分发

主要方法

/*
@return 是否消耗事件
*/
public boolean dispatchTouchEvent(event)

/*
@return 是否拦截事件
*/
public boolean onInterceptTouchEvent(event)

/*
@return 是否消耗事件
*/
public boolean onTouchEvent(event)

点击事件的传递

Activity -> Window -> DecorView -> 各层 ViewGroup -> View

分发简单原理图

最简单的分发原理如下图所示,但事件分发仍有其他特殊规则,参考分发特点
img

事件序列

从手指接触屏幕开始,到手指离开屏幕为止,为同一个事件序列。这个序列以 down 事件开始,中间含有数量不定的 move 事件,以 up 事件结束。

分发特点

在分发的过程中,对事件的处理并没有简单原理图所述的如此简单,系统在分发的环节上进行了许多特殊情况的优化,以下是这些情况的总结:

  1. 某个 ViewGroup 一旦决定拦截,那么同一事件序列只能交由它处理,且它的 onInterceptTouchEvent() 不会再调用。
  2. 某个 View/ViewGroup 一旦开始处理事件,如果它不消耗初始事件 ACTION_DOWN(即 onTouchEvent() return false),那么同一事件序列中的其他事件都不会交由它处理,并且会交给它的上层视图的 onTouchEvent() 会被调用。
  3. 如果 View/ViewGroup 不消耗 ACTION_DOWN 以外的事件,那么这个点击事件会消失,此时父元素的 onTouchEvent() 不会被调用,并且当前 View 可以持续受到后续事件,最终交由 Activity 处理。
  4. View.onTouchEvent() 默认消耗事件(return ture),除非它是不可点击的(!clickable&&!longClickable)。

由于原理较为复杂,需要结合 Log 一起理解,为节省篇幅,此处仅作列举。若需理解具体原理,推荐学习文章:更简单的学习Android事件分发