Android View 的触摸事件分发机制

509 阅读2分钟

先讲一下什么是 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()。