Android 事件分发机制

2020-10-10  本文已影响0人  JunL_Dev
Start

前言

转载

1. Android 事件分发流

图1

⚠️:图分为三层,从上到下依次是 Activity、ViewGroup、View

仔细看整个图,我们得出事件流 走向的几个结论:

  1. 如果事件不被中断,整个事件流向是一个类U型图,我们来看下这张图,可能更能理解U型图的意思。
图2

所以如果我们没有对控件里面的方法进行重写或更改返回值,而直接用 super 调用父类的默认实现,那么整个事件流向应该是从Activity---->ViewGroup--->View 从上往下调用 dispatchTouchEvent 方法,一直到叶子节点(View)的时候,再由 View--->ViewGroup--->Activity 从下往上调用 onTouchEvent 方法。

  1. dispatchTouchEvent 和 onTouchEvent 一旦return true,事件就停止传递了(到达终点)。看下图中只要 return true 事件就没再继续传下去了,对于 return true 我们经常说事件被消费了,消费了的意思就是事件走到这里就是终点,不会往下传,没有谁能再收到这个事件了。
图3
  1. dispatchTouchEvent 和 onTouchEvent return false 的时候事件都回传给父控件的 onTouchEvent 处理。
图4

看上图深蓝色的线,对于返回 false 的情况,事件都是传给父控件 onTouchEvent 处理。

⚠️:对于 dispatchTouchEvent 返回 false 的含义应该是:事件停止往子 View 传递和分发同时开始往父控件回溯(父控件的 onTouchEvent 开始从下往上回传直到某个 onTouchEvent return true),事件分发机制就像递归,return false 的意义就是递归停止然后开始回溯。

对于 onTouchEvent return false 就比较简单了,它就是不消费事件,并让事件继续往父控件的方向从下往上流动。

  1. dispatchTouchEvent、onTouchEvent、onInterceptTouchEvent

ViewGroup 和 View 的这些方法的默认实现就是会让整个事件安装 U 型完整走完,所以 return super.xxxxxx() 就会让事件依照U型的方向的完整走完整个事件流动路径),中间不做任何改动,不回溯、不终止,每个环节都走到。

图 5

所以如果看到方法 return super.xxxxx() 那么事件的下一个流向就是走 U 型下一个目标,稍微记住上面这张图,你就能很快判断出下一个走向是哪个控件的哪个函数。

  1. onInterceptTouchEvent 的作用
图 6

Intercept 的意思就拦截,每个 ViewGroup 每次在做分发的时候,问一问拦截器要不要拦截(也就是问问自己这个事件要不要自己来处理)如果要自己处理那就在 onInterceptTouchEvent 方法中 return true 就会交给自己的 onTouchEvent 的处理,如果不拦截就是继续往子控件往下传。默认是不会去拦截的,因为子 View 也需要这个事件,所以 onInterceptTouchEvent 拦截器 return super.onInterceptTouchEvent() 和 return false 是一样的,是不会拦截的,事件会继续往子 View 的 dispatchTouchEvent 传递。

  1. ViewGroup 和 View 的 dispatchTouchEvent 方法返回 super.dispatchTouchEvent() 的时候事件流走向。
图 7

首先看下 ViewGroup 的 dispatchTouchEvent,之前说的 return true 是终结传递。return false 是回溯到父 View 的 onTouchEvent,然后 ViewGroup 怎样通过 dispatchTouchEvent 方法能把事件分发到自己的onTouchEvent处理呢?

return true 和 false 都不行,那么只能通过 Interceptor 把事件拦截下来给自己的 onTouchEvent,所以 ViewGroup dispatchTouchEvent 方法的 super 默认实现就是去调用 onInterceptTouchEvent,记住这一点。

那么对于 View 的 dispatchTouchEvent return super.dispatchTouchEvent() 的时候呢事件会传到哪里呢?

很遗憾 View 没有拦截器。但是同样的道理 return true 是终结。return false 是回溯会父类的 onTouchEvent,怎样把事件分发给自己的 onTouchEvent 处理呢,那只能return super.dispatchTouchEvent,View 类的 dispatchTouchEvent() 方法默认实现就是能帮你调用 View 自己的 onTouchEvent 方法的。

说了这么多,不知道有说清楚没有,我这边最后总结一下:

ViewGroup 和 View 的 dispatchTouchEvent 是做事件分发,那么这个事件可能分发出去的四个目标:

  1. 自己消费,终结传递。------->return true ;
  2. 给自己的 onTouchEvent 处理-------> 调用 super.dispatchTouchEvent() 系统默认会去调用 onInterceptTouchEvent,在 onInterceptTouchEvent return true 就会去把事件分给自己的 onTouchEvent 处理。
  3. 传给子 View------> 调用 super.dispatchTouchEvent() 默认实现会去调用 onInterceptTouchEvent 在 onInterceptTouchEvent return false,就会把事件传给子类。
  4. 不传给子 View,事件终止往下传递,事件开始回溯,从父 View 的 onTouchEvent 开始事件从下到上回归执行每个控件的 onTouchEvent------->return false;

⚠️ 注: 由于 View 没有子 View 所以不需要 onInterceptTouchEvent 来控件是否把事件传递给子 View 还是拦截,所以 View 的事件分发调用 super.dispatchTouchEvent() 的时候默认把事件传给自己的 onTouchEvent 处理(相当于拦截),对比 ViewGroup 的 dispatchTouchEvent 事件分发,View 的事件分发没有上面提到的 4 个目标的第 3 点。

申明:开始的图片来源网络,侵删

上一篇下一篇

猜你喜欢

热点阅读