Android事件分发机制的一些基本知识

有一种学得快的方法,就是不要一次学太多。

什么是View的事件分发

在 Android 中,用户的在屏幕上的点击事件被抽象成 MotionEvent 这个类,点击事件的类型中比较重要的有 ACTION_DOWN、ACTION_MOVE、ACTION_UP 三种类型。当一个 MotionEvent 事件产生后,系统 需要把这个事件传递给一个具体的 View 来处理,而 MotionEvent 的这个分发过程,就叫 View 的事件分发过程。

点击事件分发过程中有几个重要方法?他们之间的关系是怎么的?

有三个重要的方法: dispatchTouchEvent 、onInterceptTouchEvent、onTouchEvent 。

他们之间的关系即代表了 View 的分发规则,用下面一段伪代码来表示会比较清晰:

1
2
3
4
5
6
7
8
9
public boolean dispatchTouchEvent(MotionEvent ev) { // 开始分发该事件
boolean consume = false; // 事件是否消费
if (onInterceptTouchEvent(ev)) { // 父View是否拦截该事件
consume = onTouchEvent(ev); // 父View处理该事件,判断是否要消费
} else {
consume = child.dispatchTouchEvent(ev); // 交给子View,继续往下分发。
}
return consume; // 返回值表示是否消费当前事件
}

下面对这三个方法的作用进一步描述:

dispatchTouchEvent:用来进行事件的分发,返回结果受当前 View 的 onTouchEvent 方法和下级 View 的 dispatchTouchEvent 方法决定,表示是否消费当前事件。此方法在事件传递给当前 View 时调用。

onInterceptTouchEvent:用来判断是否拦截某个事件。如果当前 View 拦截了某个事件,那么同一事件序列当中,此方法不会被再次调用,返回结果表示是否拦截当前事件。此方法在 dispatchTouchEvent 方法中被调用。

onTouchEvent:用来处理点击事件,返回结果表示是否消费当前的事件,如果不消费,则在同一事件序列中,当前 View 无法再次接收到事件。此方法在 dispatchTouchEvent 方法中被调用。

事件分发机制

这里说的事件分发机制是指从 ViewGroup 开始的事件分发机制,我们平时说的 View 的事件分发机制也是指从 ViewGroup 开始的事件分发机制。

点击事件的传递过程

点击事件的传递过程: Activity —> Window —> View

即事件总是先传递给 Activity,Activity 再传递给 Window,Window 再传递给顶级 View,顶级 View (如 DecorView) 接收到事件后,就会按照事件分发机制去分发事件,找到需要消费当前事件的消费者。

事件分发机制

对于一个根 ViewGroup 来说,当点击事件产生后,首先会传递给它,这时它的 dispatchTouchEvent 方法会被调用,如果这个 ViewGroup 的 onInterceptTouchEvent 方法返回 true,就表示它要拦截当前事件,接着事件就会交给 ViewGroup 来处理,这时它的 onTouchEvent 方法会被调用。

如果 ViewGroup 的 onInterceptTouchEvent 方法返回 false,就表示它不拦截当前事件,这时当前事件就会继续传递给它的子元素,接着子元素的 dispatchTouchEvent 方法就会被调用,如此反复直到事件被最终处理。

一个 View 是如何处理点击事件的?

它会首先判断是否设置了 onTouchListener,如果设置了则会回调 onTouchListener 的 onTouch 方法,这时事件如何处理要看 onTouch 方法的返回值。如果 onTouch 方法返回 true,表示 onTouch 方法要处理这个事件,则 onTouchEvent 将不会再被调用;如果 onTouch 方法返回 false,表示 onTouch 方法不处理这个事件,则 onTouchEvent 方法会被调用。

在 onTouchEvent 方法中,如果当前设置的监听器中有 onClickListener,那么 onClickListener 的 onClick 方法会被回调。

调用优先级:onTouchListener > onTouchEvent > onClickListener

让我们来一场点赞之交?
0%