Android 触摸事件传导流程

作者: a57ecf3aaaf2 | 来源:发表于2019-06-02 18:23 被阅读4次

    一、简介

    Android 触摸事件的分发,其实就是将一个触摸事件从顶层 View 传递到底层 View,再传递到顶层 View 的一个过程,而这个触摸事件就是一个 MotionEvent。Android 系统需要做的是,将 MotionEvent 传递给一个具体 View,由该 View 处理该事件。

    而触摸事件的传导流程中,有三个方法至关重要:dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent。

    二、触摸事件派发流程

    Android 的触摸事件分发可以用下面的伪代码简单表示:

    public boolean dispatchTouchEvent(MotionEvent event) {
          boolean handled = false;
          if (onInterceptTouchEvent(event)) {
                handled = mOnTouchListener.onTouch(this, event);
                if (!handled) {
                    handled = onTouchEvent(event);
                }
           } else {
                handled = child.dispatchTouchEvent(event);
           }
           return handled; 
    }
    

    也就是说,当一个事件产生后,会经由 ViewGroup 的 dispatchTouchEvent 方法进行派发,然后调用 onInterceptTouchEvent 方法,如果该方法返回 true,则表示拦截该事件,继续由当前 View 的 mOnTouchListener.onTouchEvent() 或 onTouchEvent() 处理。若最终没有拦截,则由子 View 继续分发,若最终子 View 没有消耗该事件,则将该事件原路返回供顶层 View 消耗,最后由 Activity 处理。

    其中,点击事件是在 onTouchEvent 中处理的,所以一旦 mOnTouchListener.onTouch() 返回 true 或未经过 onTouchEvent() 处理事件,则 onClick 方法将不会执行。

    整个触摸事件的传递流程如下:

    Activity -> Window -> View -> ... -> Window -> Activity

    其中 Window 的实现类 PhoneWindow 基本上直接调用了 DecorView 的 dispatchTouchEvent 方法,所以上述流程中 Window 节点可以忽略。

    三、触摸事件处理规则

    分发事件
    分发事件由 dispatchTouchEvent 方法负责,若事件被传递到了当前 View,则该方法一定会被执行,其返回值受当前 View 的 onTouchEvent() 和子 View 的 dispatchTouchEvent() 影响。

    View 和 ViewGroup 都存在该方法,只不过最底层的 View 没有事件拦截方法 onInterceptTouchEvent。

    拦截事件
    拦截事件由方法 onInterceptTouchEvent 负责,表示是否拦截某个事件,默认返回 false。该方法只有 ViewGroup 有,具体的 View 没有该方法,所以一旦具体的某个 View 走到了 dispatchTouchEvent 方法,一定会调用 onTouchEvent 方法。

    在同一个事件序列中,若该方法已经被调用了,那么其不会再次被调用。同一个事件序列是指:

    从手指接触到屏幕到离开屏幕的一段时间内的 down、move、up 事件的一系列过程。

    但是,父 View 的拦截事件行为可以被子 View 通过父 View 的 requestDisallowInterceptTouchEvent 方法干预(down 事件除外)。

    处理事件
    事件的处理由 onTouchEvent 方法负责,若当前 View 可被点击,则该方法默认返回 true。一旦没有消耗事件,则同一个事件序列后的其他事件将不会被传递到该 View,事件将重新交由其父 View 处理,即调用父 View 的 onTouchEvent 方法。

    View 的 enabled 属性不影响 onTouchEvent() 的返回值,只要 View 可被点击或长按,onTouchEvent() 就会返回 true。

    同一个事件序列中的一系列事件,理论上只能由同一个 View 消耗,若 View 消耗了 down 事件,但后续的事件(会收到后续事件)没有被该 View 消耗,那么其父 View 也并不会消耗,最终由 Activity 处理。

    事件分发图解

    触摸事件分发图解

    从图中可以看出,事件的 dispatchTouchEvent 由下而上(由外而内)进行传递,事件的 onTouchEvent 由上而下(由内而外)进行传递。

    当子 View 利用 requestDisallowInterceptTouchEvent 方法干预了父 View 的事件(除 down 事件外的其他事件)处理,则直接走 false 流程。

    本文由 Fynn_ 原创,未经许可,不得转载!

    相关文章

      网友评论

        本文标题:Android 触摸事件传导流程

        本文链接:https://www.haomeiwen.com/subject/whsxxctx.html