欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android touch 事件的处理流程

程序员文章站 2022-03-09 21:04:33
...

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.图例

Android touch 事件的处理流程

Android touch 事件的处理流程

Android touch 事件的处理流程

Android touch 事件的处理流程

Android touch 事件的处理流程

 

最后一图有误。如果 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