Android事件传递机制

作者: 剑舞潇湘 | 来源:发表于2016-07-04 02:21 被阅读460次

    总结,细化,推演

    一、总结

    四个事件,三个方法,两套机制

    1.1 四个事件

    • Down
    • Move
    • Up/Cancel

    1.2 三个方法

    • dispatchTouchEvent
    • onInterceptTouchEvent
    • onTouchEvent

    1.3 两套机制

    Talk is cheap, show you the code.

    ViewGroup处理机制:

    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (!onInterceptTouchEvent(ev)) {                   // 1. 判断是否拦截
            for (int i = childrenCount - 1; i >= 0; i--) {  // 2. 逆序遍历子View,寻找意欲消费该事件的子View
                if (children[i].dispatchTouchEvent(ev)) {
                    return true;
                }
            }
        }
        return super.dispatchTouchEvent(ev);               // 3. 如果没有子View消费事件,则走View处理机制
    }
    

    View处理机制:

    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (onTouchListener != null) {
            return onTouchListener.onTouch(ev) || onTouchEvent(ev);
        }
        return onTouchEvent(ev);
    }
    

    注意
    1、上述机制是极度简化后的(后文详述)
    2、ViewGroup本身也是View

    二、细化

    2.1 四个事件

    只考虑单点触控的情况下,一次手势操作产生的事件序列如下图所示:


    基本事件序列

    注意
    事件消费以手势为单位,如果View不消费Down事件,则它将不再收到其它事件;反之,如果它消费了Down事件,则必然以一个Up或Cancel事件结束。

    2.2 三个方法

    dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent都接收一个TouchEvent作为参数,返回值类型都是boolean。

    dispatchTouchEvent自上而下分发,onTouchEvent自下而上处理,onInterceptTouchEvent居中拦截,构成了Android事件的处理机制。

    2.2.1 dispatchTouchEvent

    dispatchTouchEvent定义在Activity、ViewGroup和View中,控制TouchEvent走向,其目的就是找出哪个View应该处理该TouchEvent,简言之,它用于事件的分发。

    Activity.dispatchTouchEvent总是最先收到事件,经过一系列下发后,传递给布局。本文只考虑布局对手势事件的处理。

    dispatchTouchEvent有几个原则非常关键

    1. 其对Down事件的返回值表征是否消费该事件(对其它事件的返回值无所谓)
    2. 自上而下分发,采用逐层负责制
    3. 分发之前先判断是否要拦截
    2.2.2 onInterceptTouchEvent

    onInterceptTouchEvent定义在ViewGroup中,用于拦截事件。

    onInterceptTouchEvent被调用需要满足两个条件:

    1. 当前传递的是Down事件或者有子View消费了之前的Down事件
    2. 允许拦截

    如果onInterceptTouchEvent拦截的是Down事件,Down事件不会继续向下传递;如果拦截的是Move或Up事件,则会下发Cancel事件给下层。

    onInterceptTouchEvent一旦返回true,就不会再调用。

    2.2.3 onTouchEvent

    onTouchEvent定义在Activity、ViewGroup和View中,消费事件。

    2.3 两套机制

    1.3节中所示的机制确切来说是不正确的,实际的事件传递机制要复杂得多。

    Android事件处理涉及三个操作:分发、拦截与消费。

    • 分发
    • dispatchTouchEvent负责分发
    • 分发自上而下
    • 分发前判断是否拦截
    • dispatchTouchEvent对Down事件返回true表征View/ViewGroup消费该事件
    • dispatchTouchEvent对其余事件的返回值对分发没有任何影响
    • ViewGroup会逆序遍历边界包含触控点的所有子View,调用其dispatchTouchEvent判断其是否消费
    • 一旦找到消费事件的子View
      • ViewGroup会停止遍历
      • 后续事件会直接分发给该子View,不再遍历
    • 拦截
    • onInterceptTouchEvent负责拦截
    • onInterceptTouchEvent返回true表征拦截
    • 如果ViewGroup A拦截Down事件
      • 所有事件由拦截事件的ViewGroup处理,不向下分发
    • 如果ViewGroup A拦截Move/Up事件
      • 事件转为Cancel向下分发
      • A.onTouchEvent在本次事件中不会被调用
      • A.dispatchTouchEvent会将后续事件直接传递给A.onTouchEvent,不向下分发
    • 一旦onInterceptTouchEvent返回true,就不会再被调用
    • 消费
      • OnTouchListener或onTouchEvent负责消费
      • OnTouchListener优先于onTouchEvent
      • 如果OnTouchListener.onTouch返回true,则onTouchEvent不会再被调用
      • 如果没有注册OnTouchListener或OnTouchListener.onTouch返回false,onTouchEvent会再被调用

    第三章通过推演详述这两套机制。

    三、推演

    假定有一个如下布局:L里包了一个R,R里包了B、T1、T2三个子View,T2叠在T1上。



    L继承自LinearLayout,R继承自RelativeLayout,B继承自Button,T1、T2继承自TextView,在它们各事件方法的头部和尾部分别插入日志以观察其行为:

    // public boolean onInterceptTouchEvent(MotionEvent ev) {
    // public boolean onTouchEvent(MotionEvent event) {
    public boolean dispatchTouchEvent(MotionEvent ev) {
        L.e(MotionEvent.actionToString(ev.getAction()));
        boolean result = super.dispatchTouchEvent(ev);
        L.e(MotionEvent.actionToString(ev.getAction()) + " " + result);
        return result;
    }
    

    默认情况
    在T1的右侧(未被T2覆盖的部分)滑动手指,生成如下日志:

    1. L.dispatchTouchEvent(L.java:41) ==> ACTION_DOWN
    2. L.onInterceptTouchEvent(L.java:33) ==> ACTION_DOWN
    3. L.onInterceptTouchEvent(L.java:35) ==> ACTION_DOWN false
    4.  R.dispatchTouchEvent(R.java:45) ==> ACTION_DOWN
    5.  R.onInterceptTouchEvent(R.java:37) ==> ACTION_DOWN
    6.  R.onInterceptTouchEvent(R.java:39) ==> ACTION_DOWN false
    7.      T1.dispatchTouchEvent(T1.java:35) ==> ACTION_DOWN
    8.      T1.onTouchEvent(T1.java:43) ==> ACTION_DOWN
    9.      T1.onTouchEvent(T1.java:45) ==> ACTION_DOWN false
    10.     T1.dispatchTouchEvent(T1.java:37) ==> ACTION_DOWN false
    11. R.onTouchEvent(R.java:53) ==> ACTION_DOWN
    12. R.onTouchEvent(R.java:55) ==> ACTION_DOWN false
    13. R.dispatchTouchEvent(R.java:47) ==> ACTION_DOWN false
    14. L.onTouchEvent(L.java:49) ==> ACTION_DOWN
    15. L.onTouchEvent(L.java:51) ==> ACTION_DOWN false
    16. L.dispatchTouchEvent(L.java:43) ==> ACTION_DOWN false
    

    从日志中可以看出,事件传递经历了如下步骤:

    1. 首先产生的是Down事件,传递给L.dispatchTouchEvent
    2. L随之调用自身的onInterceptTouchEvent方法
    3. L.onInterceptTouchEvent返回false,表明L不拦截
    4. L于是把事件分发给R(调用R.dispatchTouchEvent)
    5. 同样的,R先调用自身的onInterceptTouchEvent
    6. R.onInterceptTouchEvent返回false,表明R也不拦截
    7. R于是把事件分发给T1(调用T1.dispatchTouchEvent)
    8. T1是普通View,不再需要向下分发,于是调用自身的onTouchEvent
      (自此,事件分发完成,开始处理事件)
    9. T1.onTouchEvent返回false
    10. T1.dispatchTouchEvent收到T1.onTouchEvent的返回值,同样返回false,表明T1不消费Down事件
      (第9、10步参见1.3节View处理机制)
    11. R根据T1.dispatchTouchEvent的返回值判断T1没有消费事件,于是尝试自己处理该事件,调用自身的onTouchEvent
    12. R.onTouchEvent返回false
    13. 从而导致R.dispatchTouchEvent返回false,表明R不消费Down事件
    14. 由于R没有消费事件,L尝试自己处理事件,调用自身的onTouchEvent
    15. L.onTouchEvent返回false
    16. 从而导致L.dispatchTouchEvent返回false
      (由于Down事件没有被消费,因此它们都将不再收到其它事件,事件处理结束)

    结论
    1、dispatchTouchEvent自上而下分发
    2、onTouchEvent自下而上消费
    3、ViewGroup.dispatchTouchEvent向下分发之前,会先调用onInterceptTouchEvent
    4、如果Down事件没有被消费,将不再收到其余事件(Move,Up)

    消费事件
    如果View是clickable的,或者View注册了OnTouchListener且其onTouch方法返回true,或者实现了自定义的返回值为true的onTouchEvent,则认为View消费了事件。

    根据我们的假定,B继承自Button,它是clickable的,因此可用于做消费事件的实验,但为了同时说明ViewGroup寻找子View的机制,我们在T1上注册一个OnTouchListener回调并返回true。

    在T2上点击,日志如下:

    1. L.dispatchTouchEvent(L.java:41) ==> ACTION_DOWN
    2. L.onInterceptTouchEvent(L.java:33) ==> ACTION_DOWN
    3. L.onInterceptTouchEvent(L.java:35) ==> ACTION_DOWN false
    4.     R.dispatchTouchEvent(R.java:43) ==> ACTION_DOWN
    5.     R.onInterceptTouchEvent(R.java:35) ==> ACTION_DOWN
    6.     R.onInterceptTouchEvent(R.java:37) ==> ACTION_DOWN false
    7.          T2.dispatchTouchEvent(T2.java:35) ==> ACTION_DOWN
    8.          T2.onTouchEvent(T2.java:43) ==> ACTION_DOWN
    9.          T2.onTouchEvent(T2.java:45) ==> ACTION_DOWN false
    10.         T2.dispatchTouchEvent(T2.java:37) ==> ACTION_DOWN false
    11.         T1.dispatchTouchEvent(T1.java:35) ==> ACTION_DOWN
    12.         MainActivity$1.onTouch(MainActivity.java:21) ==> ACTION_DOWN true
    13.         T1.dispatchTouchEvent(T1.java:37) ==> ACTION_DOWN true
    14.    R.dispatchTouchEvent(R.java:45) ==> ACTION_DOWN true
    15. L.dispatchTouchEvent(L.java:43) ==> ACTION_DOWN true
    
    16. L.dispatchTouchEvent(L.java:41) ==> ACTION_UP
    17. L.onInterceptTouchEvent(L.java:33) ==> ACTION_UP
    18. L.onInterceptTouchEvent(L.java:35) ==> ACTION_UP false
    19.     R.dispatchTouchEvent(R.java:43) ==> ACTION_UP
    20.     R.onInterceptTouchEvent(R.java:35) ==> ACTION_UP
    21.     R.onInterceptTouchEvent(R.java:37) ==> ACTION_UP false
    22.         T1.dispatchTouchEvent(T1.java:35) ==> ACTION_UP
    23.         MainActivity$1.onTouch(MainActivity.java:21) ==> ACTION_UP true
    24.         T1.dispatchTouchEvent(T1.java:37) ==> ACTION_UP true
    25.     R.dispatchTouchEvent(R.java:45) ==> ACTION_UP true
    26. L.dispatchTouchEvent(L.java:43) ==> ACTION_UP true
    

    日志分析:
    日志1至日志10与默认情况无异,下面主要说说几处不同。
    11至13:事件透过T2继续向T1分发,且T1注册的回调返回了true,因此T1消费了Down事件
    14至15:由于有子View消费了事件,因此L、R的onTouchEvent方法没有被调用
    16至26:由于Down事件被消费,因此系统继续下发后续事件(Up)
    (手指滑动小于20像素,不会产生Move事件,本例为简化没有令其产生)
    另外注意,R没有将Up事件传递给T2,而是直接传给了T1

    结论
    1、如果消费了Down事件,则会继续收到后续事件
    2、ViewGroup会以子View添加顺序的逆序查找边界包含触控点的所有子View
    (2.1 事实上,如果遍历时发现某子View消费了该事件,ViewGroup会停止遍历)
    3、一旦查找到消费事件的子View,后续事件会直接传递给它,不会再遍历

    关于结论中2.1的论证,可以做这样一个实验:
    在T2上注册OnTouchListener回调,实验方式不变,会发现事件不会传递给T1,而是由T2消费Down和Up事件。

    如何判断事件是否被消费?
    关于事件是否被消费,有说法说是看onTouchEvent是否返回true,这是不对的,实际上要看dispatchTouchEvent是否返回true,之所以会有这种说法,是因为默认情况下如果onTouchEvent返回true,则dispatchTouchEvent必然返回true(见1.3)。

    做两个实验验证:

    1. 令T1.onTouchEvent返回true,而T1.dispatchTouchEvent返回false
    2. 令T1.onTouchEvent返回false,而T1.dispatchTouchEvent返回true

    实验一日志输出除第9条外与默认情况完全一样,这里从略。
    实验二日志如下:

    1. L.dispatchTouchEvent(L.java:41) ==> ACTION_DOWN
    2. L.onInterceptTouchEvent(L.java:33) ==> ACTION_DOWN
    3. L.onInterceptTouchEvent(L.java:35) ==> ACTION_DOWN false
    4.  R.dispatchTouchEvent(R.java:45) ==> ACTION_DOWN
    5.  R.onInterceptTouchEvent(R.java:37) ==> ACTION_DOWN
    6.  R.onInterceptTouchEvent(R.java:39) ==> ACTION_DOWN false
    7.          T1.dispatchTouchEvent(T1.java:35) ==> ACTION_DOWN
    8.          T1.onTouchEvent(T1.java:44) ==> ACTION_DOWN
    9.          T1.onTouchEvent(T1.java:46) ==> ACTION_DOWN false
    10.         T1.dispatchTouchEvent(T1.java:38) ==> ACTION_DOWN true
    11.     R.dispatchTouchEvent(R.java:47) ==> ACTION_DOWN true
    12. L.dispatchTouchEvent(L.java:43) ==> ACTION_DOWN true
    
    13. L.dispatchTouchEvent(L.java:41) ==> ACTION_UP
    14. L.onInterceptTouchEvent(L.java:33) ==> ACTION_UP
    15. L.onInterceptTouchEvent(L.java:35) ==> ACTION_UP false
    16.     R.dispatchTouchEvent(R.java:45) ==> ACTION_UP
    17.     R.onInterceptTouchEvent(R.java:37) ==> ACTION_UP
    18.     R.onInterceptTouchEvent(R.java:39) ==> ACTION_UP false
    19.         T1.dispatchTouchEvent(T1.java:35) ==> ACTION_UP
    20.         T1.onTouchEvent(T1.java:44) ==> ACTION_UP
    21.         T1.onTouchEvent(T1.java:46) ==> ACTION_UP false
    22.         T1.dispatchTouchEvent(T1.java:38) ==> ACTION_UP true
    23.     R.dispatchTouchEvent(R.java:47) ==> ACTION_UP true
    24. L.dispatchTouchEvent(L.java:43) ==> ACTION_UP true
    

    从日志中可以看出,
    (实验1)虽然T1.onTouchEvent返回true,但由于T1.dispatchTouchEvent返回false,系统仍然认为T1没有消费Down事件,因此T1不再收到后续事件。
    (实验2)反之,强制使T1.dispatchTouchEvent返回true后,T1(及T1的父控件L、R)会收到后续事件(Up),
    由此可知

    dispatchTouchEvent返回true <=> View消费了事件

    逐层负责制
    为了说明事件下发是采用逐层负责制,做两个实验(点击T1):

    1. 令T1.dispatchTouchEvent返回false(默认情况),R.dispatchTouchEvent返回true(点击T1)
    2. 令R.dispatchTouchEvent返回false,L.dispatchTouchEvent返回true(点击B)

    实验1日志如下:

    1.  L.dispatchTouchEvent(L.java:41) ==> ACTION_DOWN
    2.  L.onInterceptTouchEvent(L.java:33) ==> ACTION_DOWN
    3.  L.onInterceptTouchEvent(L.java:35) ==> ACTION_DOWN false
    4.      R.dispatchTouchEvent(R.java:43) ==> ACTION_DOWN
    5.      R.onInterceptTouchEvent(R.java:35) ==> ACTION_DOWN
    6.      R.onInterceptTouchEvent(R.java:37) ==> ACTION_DOWN false
    7.          T1.dispatchTouchEvent(T1.java:35) ==> ACTION_DOWN
    8.          T1.onTouchEvent(T1.java:43) ==> ACTION_DOWN
    9.          T1.onTouchEvent(T1.java:45) ==> ACTION_DOWN false
    10.         T1.dispatchTouchEvent(T1.java:37) ==> ACTION_DOWN false
    11.     R.onTouchEvent(R.java:52) ==> ACTION_DOWN
    12.     R.onTouchEvent(R.java:54) ==> ACTION_DOWN false
    13.     R.dispatchTouchEvent(R.java:46) ==> ACTION_DOWN true
    14. L.dispatchTouchEvent(L.java:43) ==> ACTION_DOWN true
    
    15. L.dispatchTouchEvent(L.java:41) ==> ACTION_UP
    16. L.onInterceptTouchEvent(L.java:33) ==> ACTION_UP
    17. L.onInterceptTouchEvent(L.java:35) ==> ACTION_UP false
    18.     R.dispatchTouchEvent(R.java:43) ==> ACTION_UP
    19.     R.onTouchEvent(R.java:52) ==> ACTION_UP
    20.     R.onTouchEvent(R.java:54) ==> ACTION_UP false
    21.     R.dispatchTouchEvent(R.java:46) ==> ACTION_UP true
    22. L.dispatchTouchEvent(L.java:43) ==> ACTION_UP true
    

    实验2日志如下:

    1.  L.dispatchTouchEvent(L.java:41) ==> ACTION_DOWN
    2.  L.onInterceptTouchEvent(L.java:33) ==> ACTION_DOWN
    3.  L.onInterceptTouchEvent(L.java:35) ==> ACTION_DOWN false
    4.      R.dispatchTouchEvent(R.java:43) ==> ACTION_DOWN
    5.      R.onInterceptTouchEvent(R.java:35) ==> ACTION_DOWN
    6.      R.onInterceptTouchEvent(R.java:37) ==> ACTION_DOWN false
    7.          B.dispatchTouchEvent(B.java:35) ==> ACTION_DOWN
    8.          B.onTouchEvent(B.java:43) ==> ACTION_DOWN
    9.          B.onTouchEvent(B.java:45) ==> ACTION_DOWN true
    10.         B.dispatchTouchEvent(B.java:37) ==> ACTION_DOWN true
    11.     R.dispatchTouchEvent(R.java:46) ==> ACTION_DOWN false
    12. L.onTouchEvent(L.java:50) ==> ACTION_DOWN
    13. L.onTouchEvent(L.java:52) ==> ACTION_DOWN false
    14. L.dispatchTouchEvent(L.java:44) ==> ACTION_DOWN true
    
    15. L.dispatchTouchEvent(L.java:41) ==> ACTION_UP
    16. L.onTouchEvent(L.java:50) ==> ACTION_UP
    17. L.onTouchEvent(L.java:52) ==> ACTION_UP false
    18. L.dispatchTouchEvent(L.java:44) ==> ACTION_UP true
    

    从实验1日志可以看出,T1没有消费Down事件,R消费了Down事件,所以Up事件继续传递给R,但R不再向T1分发。
    从实验2日志可以看出,虽然B消费了Down事件,但由于R.dispatchTouchEvent返回了false,表征R没有消费Down事件,因此系统不再向R下发后续事件,也就不会向B下发后续事件。

    结论
    如果ViewGroup没有消费Down事件,即使其子View消费了Down事件,该ViewGroup及其子View都不会再收到后续事件。

    拦截机制
    做两个实验:

    1. (拦截Down事件)令L.onInterceptTouchEvent(ACTION_DOWN)返回true,同时L.dispatchTouchEvent(ACTION_DOWN)返回true,其它默认(点击T1)
    2. (拦截Move事件)令L.onInterceptTouchEvent(ACTION_MOVE)返回true,其它默认(点击B)

    实验1日志输出如下:

    1.  L.dispatchTouchEvent(L.java:44) ==> ACTION_DOWN
    2.  L.onInterceptTouchEvent(L.java:33) ==> ACTION_DOWN
    3.  L.onInterceptTouchEvent(L.java:38) ==> ACTION_DOWN true
    4.  L.onTouchEvent(L.java:55) ==> ACTION_DOWN
    5.  L.onTouchEvent(L.java:57) ==> ACTION_DOWN false
    6.  L.dispatchTouchEvent(L.java:49) ==> ACTION_DOWN true
    
    7.  L.dispatchTouchEvent(L.java:44) ==> ACTION_UP
    8.  L.onTouchEvent(L.java:55) ==> ACTION_UP
    9.  L.onTouchEvent(L.java:57) ==> ACTION_UP false
    10. L.dispatchTouchEvent(L.java:49) ==> ACTION_UP false
    

    实验2日志输出如下:

    1.  L.dispatchTouchEvent(L.java:44) ==> ACTION_DOWN
    2.  L.onInterceptTouchEvent(L.java:33) ==> ACTION_DOWN
    3.  L.onInterceptTouchEvent(L.java:38) ==> ACTION_DOWN false
    4.      R.dispatchTouchEvent(R.java:43) ==> ACTION_DOWN
    5.      R.onInterceptTouchEvent(R.java:35) ==> ACTION_DOWN
    6.      R.onInterceptTouchEvent(R.java:37) ==> ACTION_DOWN false
    7.          B.dispatchTouchEvent(B.java:35) ==> ACTION_DOWN
    8.          B.onTouchEvent(B.java:43) ==> ACTION_DOWN
    9.          B.onTouchEvent(B.java:45) ==> ACTION_DOWN true
    10.         B.dispatchTouchEvent(B.java:37) ==> ACTION_DOWN true
    11.     R.dispatchTouchEvent(R.java:45) ==> ACTION_DOWN true
    12. L.dispatchTouchEvent(L.java:46) ==> ACTION_DOWN true
    
    13. L.dispatchTouchEvent(L.java:44) ==> ACTION_MOVE
    14. L.onInterceptTouchEvent(L.java:33) ==> ACTION_MOVE
    15. L.onInterceptTouchEvent(L.java:38) ==> ACTION_MOVE true
    16.     R.dispatchTouchEvent(R.java:43) ==> ACTION_CANCEL
    17.     R.onInterceptTouchEvent(R.java:35) ==> ACTION_CANCEL
    18.     R.onInterceptTouchEvent(R.java:37) ==> ACTION_CANCEL false
    19.         B.dispatchTouchEvent(B.java:35) ==> ACTION_CANCEL
    20.         B.onTouchEvent(B.java:43) ==> ACTION_CANCEL
    21.         B.onTouchEvent(B.java:45) ==> ACTION_CANCEL true
    22.         B.dispatchTouchEvent(B.java:37) ==> ACTION_CANCEL true
    23.     R.dispatchTouchEvent(R.java:45) ==> ACTION_CANCEL true
    24. L.dispatchTouchEvent(L.java:46) ==> ACTION_MOVE true
    
    25. L.dispatchTouchEvent(L.java:44) ==> ACTION_MOVE
    26. L.onTouchEvent(L.java:52) ==> ACTION_MOVE
    27. L.onTouchEvent(L.java:54) ==> ACTION_MOVE false
    28. L.dispatchTouchEvent(L.java:46) ==> ACTION_MOVE false
    
    29. L.dispatchTouchEvent(L.java:44) ==> ACTION_UP
    30. L.onTouchEvent(L.java:52) ==> ACTION_UP
    31. L.onTouchEvent(L.java:54) ==> ACTION_UP false
    32. L.dispatchTouchEvent(L.java:46) ==> ACTION_UP false
    

    实验1日志分析:

    1. (日志1至6)L拦截了Down事件,事件由L进行处理,不再向下分发
    2. (日志7至10)系统下发Up事件给L后,L不再调用自身的onInterceptTouchEvent。

    实验2日志分析:

    1. L拦截了第一个Move事件
    • 该事件转为Cancel事件,继续向下分发
    • L.onTouchEvent不会被调用
    1. 后续事件(Move/Up)直接由L处理
    • 不再调用onInterceptTouchEvent
    • 也不再向下分发

    结论
    1、 如果ViewGroup拦截了Down事件,则该ViewGroup不向下分发任何事件,该ViewGroup会消费整个手势事件。
    2、如果ViewGroup拦截了Move事件,则该事件会转为Cancel事件继续向下分发,但不会调用自身的onTouchEvent,而后续的事件则会直接有该ViewGroup处理,不在询问是否拦截,也不再向下分发
    3、一旦onInterceptTouchEvent返回true,就不会再被调用
    4、 如果子View没有消费事件而ViewGroup消费了Down事件,则后续不会再调用ViewGroup的onInterceptTouchEvent

    拓展阅读

    相关文章

      网友评论

      • 皮球二二:有个问题想问下,默认情况下如果给t1或者t2的down返回true,难道收不到后续事件?
        剑舞潇湘:@r17171709 如果不干涉ViewGroup,子View消费事件会导致父控件消费事件,如此逐层向上传递,因此会收到后续事件。
        我那个结论的前提是“强制使ViewGroup不消费事件”
        皮球二二:@剑舞潇湘 我仅仅修改子view的TouchEvent的down改成true,对于你的那条结论“如果ViewGroup没有消费Down事件,即使其子View消费了Down事件,该ViewGroup及其子View都不会再收到后续事件。”产生质疑
        剑舞潇湘:@r17171709 如果修改返回值就不是默认情况了。另外你说的是修改方法的返回值?

      本文标题:Android事件传递机制

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