Android touch 事件的处理流程
1.与 touch 事件相关的主要处理方法是:
dispatchTouchEvent (onInterceptTouchEvent + onTouchEvent)
onInterceptTouchEvent 只存在于 ViewGroup 中。
2.在页面,touch事件的传递顺序,从外层到内层依次是 Activity,ViewGroup 和 View。
3.Activity 实际上是以 ViewGroup 的身份来处理事件。逻辑如下。
//Activiyt 的 dispatchTouchEvent 源码
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
//window 的 superDispatchTouchEvent 源码
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
//window 中 DecorView 处理 touch 事件的源码
private DecorView mDecor;
private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
}
可以看出 decorView 处理 dispatchTouchEvent 依赖于 FrameLyaout 的相应方法。FrameLyaout 本身不处理 touch 事件,最后touch 事件由 FrameLyaout 的父类 ViewGroup 处理。
所以 Activity -> ViewGroup -> View 的层次,实际上可以简化为 ViewGroup -> View。
4.ViewGroup 的 touch 事件处理逻辑如下
//ViewGroup dispatchTouchEvent 方法的逻辑类似于以下代码
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean result = false; // 默认状态为没有消费过
if (!onInterceptTouchEvent(ev)) { // 如果没有拦截交给子View
result = child.dispatchTouchEvent(ev);
}
if (!result) { // 如果事件没有被消费,询问自身onTouchEvent
result = onTouchEvent(ev);
}
return result;
}
5.View 的 dispatchTouchEvent 方法处理逻辑如下
//View 的 dispatchTouchEvent 方法的源码逻辑类似于如下代码
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
return result;
}
view 的 onTouchEvent 中,只要 clickable 属性为 true,那么其返回值就是 true。只要 view.setOnClickListener(null or not null)执行过,clickable = true。所以只要 view 调用过 setOnClickListener 方法,view 的 dispatchTouchVent 方法的返回值就是 true。
6.默认情况的方法调用链如下:
ACTION_DOWN 时
Activity.dispatchTouchEvent -> ViewGroup.dispatchTouchEvent -> ViewGroup.onInterceptTouchEvent(return false)
-> View.dispatchTouchEvent -> View.onTouchEvent(return false) -> View.dispatchTouchEvent (return false)
-> ViewGroup.onTouchEvent(return false) -> ViewGroup.dispatchTouchEvent(return false)
-> Activity.onTouchEvent(return false) -> Activity.dispatchTouchEvent(return false)
ACTION_MOVE 和 ACTION_UP 时
由于在 ACTION_DOWN 时 ViewGroup 和 View 处理 touch 事件的方法返回值都是 false,所以 ACTION_MOVE 和 ACTION_UP 就不再经过它们的处理,直接由 Activity 处理
Activity.dispatchTouchEvent -> Activity.onTouchEvent(return false) -> Activity.dispatchTouchEvent(return false)
7.图例
最后一图有误。如果 view.onTouch 方法返回 false,还是会经过view.onTouchEvent 方法的。
8.结论
1)touch 事件从父视图向子视图传递。父视图先询问子视图是否处理,如果子视图不处理,则由自己的相关方法处理。
所以,如果父视图没有拦截 touch 事件(onInterceptTouchEvent return false),则子视图的事件处理方法优先。
2)如果子视图不处理 ACTION_DOWN 事件,则 ACTION_MOVE 和 ACTION_UP 事件将不会传递到子视图。
3) onClick 方法是在 ACTION_UP 事件之后被触发。
参考 https://blog.csdn.net/u012858313/article/details/54315091
下一篇: Android 快速开发框架