先讲一下什么是 MotionEvent
用户在android手机上的每次触摸都会转化成一个对应的触摸事件对象。这个对象就是 MotionEvent, 它包含这次触摸的所有相关信息,例如:手指点击的位置,动作类型等。
主要的 MotionEvent 有四种:
| 事件类型 | 含义 |
|---|---|
| MotionEvent.ACTION_DOWN | 手指按下 |
| MotionEvent.ACTION_MOVE | 手指在屏幕上拖动 |
| MotionEvent.ACTION_UP | 手指抬起 |
| MotionEvent.ACTION_CANCEL | 事件取消(不是用户行为) |
一次完整的触摸流程一般由以下一系列事件组成:1 次 ACTION_DOWN + 0-N 次 ACTION_MOVE + 1 次 ACTION_UP
View 的事件分发其实就是对 MotionEvent 的分发。
如何分发
分发过程的传递顺序如下:Activity -> Window -> ViewGroup -> View
分发流程的控制由三个函数完成:
public boolean dispatchTouchEvent(MotionEvent event)
进行事件的分发,一般会调用自己的或 children 的 onDispatchEvent 方法。返回值表示是否消耗当前事件。
public boolean onInterceptTouchEvent(MotionEvent event)
一般会被 dispatchTouchEvent 调用,用于判断当前 view 是否需要拦截某个事件,如果拦截,那么接下来的一系列事件都会交给这个 view 进行处理。
public boolean onTouchEvent(MotionEvent event)
对点击事件进行处理,返回当前 view 是否处理此事件。如果不处理,那么在同一事件序列里,当前 view 不会再接收到事件
分发过程
1. Activity 最先收到事件
当一个触摸操作发生时,时间最先被传递给当前 activity 的 dispatchTouchEvent() 进行分发。当前 Activity 会把事件通过 window 传给顶层 view。如果顶层 view 不处理,activity 则会调用自己的 onTouchEvent(),自己进行处理。
2. 上层 View Group 对事件进行拦截或分发
ViewGroup 的 dispatchTouchEvent() 收到事件后,会调用 onInterceptTouchEvent(),如果 ViewGroup 的 onInterceptTouchEvent() 返回 true 决定拦截事件。那么之后的一系列事件都会交给他处理。否则,事件会被传给下面子 view 处理, 子 View 的 dispatchTouchEvent() 会被调用。如果子元素的 dispatchTouchEvent() 返回 true,则表示该事件交给了这个子元素,分发结束。
3. View 对事件的处理
View 对事件的处理相对简单,因为他不用向下分发事件。view 的 dispatchTouchEvent() 会先调用 OnTouchListener 的 onTouch() 函数,如果返回 true,则消耗该点击事件。如果没有设置listener,则调用 view 的 onTouchEvent()。