Android 的事件分发、传递、处理机制

时间:2022-07-12 17:46:42

1.点击事件传递规则

1.1 ViewGroup 中逻辑

  1. 对于一个根 ViewGroup,点击事件产生后,首先传递给它,调用它的 dispatchTouchEvent 方法

  2. 如果这个 ViewGroup 的 onInterceptTouchEvent 返回 true ,表示它要拦截该事件,接着事件会交由 该 ViewGroup 处理,即调用 它的 onTouchEvent 方法

  3. 如果 onInterceptTouchEvent 返回 false,事件会传递给它的 子View,接着 子View 调用它的 dispatchTouchEvent 方法。

1.2 onTouchEvent 返回 false

事件传递,遵循规则如下:Activity –> Window –> View(*View)

如果一个 View(无子View) 的 onTouchEvent 返回 false,那么它父容器的 onTouchEvent 会被调用,一次类推,如果所有的元素都不处理该事件,那么这个事件最终会传给 Activity 处理,即 Activity 的 ontouchEvent 会被调用。

1.3 总结,更好地理解整个传递机制

Android 的事件分发、传递、处理机制
Android 的事件分发、传递、处理机制
Android 的事件分发、传递、处理机制

2.*View对点击事件的分发过程

2.1 大致逻辑

如果事件能够传递给当前View,那么此方法一定会被调用

返回结果受当前View 的 onTouchEvent 和下级 View 的 dispatchTouchEvent 方法的影响表示是否消耗当前事件

Android 的事件分发、传递、处理机制

2.2 当前View是否拦截点击事件源码分析

Android 的事件分发、传递、处理机制

Android 的事件分发、传递、处理机制

结论

  • 当ViewGroup 决定拦截事件后,那么后续的点击事件都会交给它处理并且不再调用它的 onInterceptTouchEvent 方法

  • onInterceptTouchEvent 不是每次事件都会被调用,如果想提前处理所有的点击事件,要选择 dispatchTouchEvent 方法,只要能传递给当前 View ,他每次都会被调用

  • FLAG_DISALLOW_INTERCEPT 可以用于处理滑动冲突

2.3 ViewGroup 不拦截时事件分发的源码

首先会遍历 ViewGroup 的所有子元素,然后判断子元素是否可以接收点击事件(子元素是否在播动画 && 点击事件的坐标是否落在子元素的区域内),如果某个子元素满足这两个条件,事件就会传递给它来处理。

Android 的事件分发、传递、处理机制

如果子元素的 dispatchTouchEvent 返回 true,暂不考虑如何在子元素内部怎么分发,mFirstTouchTarget 就会被赋值同时跳出 for 循环

Android 的事件分发、传递、处理机制

如果子元素的 dispatchTouchEvent 返回 false,ViewGroup 就会把事件分发给下一个子元素(如果有)

  • Activity.dispatchTouchEvent 返回 true |fasle 事件只在 Activity 的 dispatchTouchEvent 进行处理。

如果遍历所有的子元素后事件都没有被合适的处理,这包含两种情况,1:ViewGroup 没有子元素,2:子元素处理了点击事件,但是 dispatchTouchEvent 中返回了 false (一般是因为子元素在 onTouchEvent 中返回了 false),这就验证了下面这句话:

Android 的事件分发、传递、处理机制

另外,在这两种情况下,ViewGroup 会自己处理点击事件

Android 的事件分发、传递、处理机制
Android 的事件分发、传递、处理机制

注意第三个参数 child 为 null , 2.3 一开始的代码里有分析,它会调用

super.dispatchTouchEvent(event)

很显然,这里会转到 View 的 dispatchTouchEvent 方法,即点击事件交由 View 来处理

  • View.dispatchTouchEvent 返回super.dispatchTouchEvent(ev); 事件会传递给当前View的 onTouchEvent 进行处理;

  • ViewGroup.dispatchTouchEvent 返回super.dispatchTouchEvent(ev); 事件会传递给当前ViewGroup的 onInterceptTouchEvent 进行处理;

3. View(不含ViewGroup)处理事件逻辑

右侧的是 onTouchEvent 中的 onClick 方法,也在下面

Android 的事件分发、传递、处理机制

onTouchEvent 方法中的逻辑:

Android 的事件分发、传递、处理机制

4.事件拦截 onInterceptTouchEvent

onInterceptTouchEvent 的事件拦截逻辑如下:

  • 如果 onInterceptTouchEvent 返回 true,则表示将事件会被拦截,事件最终在当前ViewGroup的 onTouchEvent 进行处理;

  • 如果 onInterceptTouchEvent 返回 false,则表示将事件没被拦截,事件会被传递到子 View上,再由子 View 的 dispatchTouchEvent来开始这个事件的分发;

  • 如果 onInterceptTouchEvent 返回 super.onInterceptTouchEvent(ev),事件默认不会被拦截,处理方式同返回false一样。

5.事件响应 onTouchEvent

onTouchEvent 的事件响应逻辑如下:

  • 如果 onTouchEvent返回了 true 则会接收并消费该事件。

  • 如果 onTouchEvent返回了 false 那么这个事件会从当前 View 向上传递,并且都是由上层 View 的 onTouchEvent 来接收,

    如果传递到上面的 onTouchEvent 也返回 false,这个事件就会“消失”,而且接收不到下一次事件。

  • 如果返回 super.onTouchEvent(ev);

    Activity.super.onTouchEvent(ev); 默认 返回 false

    ViewGroup.super.onTouchEvent(ev); 默认 返回 false

    View.super.onTouchEvent(ev); Clickable 或 LongClickable 一个为true,就默认 返回 true,不管它是不是 disable 状态

6. 事件分发机制 完整流程图

Android 的事件分发、传递、处理机制