探索Android事件分发机制,带你通过源码分析事件分发流程——ViewGroup篇

本文详细探讨了Android ViewGroup的事件分发流程,从事件传递顺序、关键概念如pointer、TouchTarget到dispatchTransformedTouchEvent方法,再到ViewGroup的事件分发机制的三个主要部分:拦截判断、Down事件确定分发目标和事件分发给目标。通过源码分析,揭示了事件如何在ViewGroup及其子View间传递,以及在多点触控和拦截情况下的处理策略。
摘要由CSDN通过智能技术生成

通过上一篇文章(探索Android事件分发机制,带你通过源码分析事件分发流程——View篇)我们已经了解了View的事件分发过程,还没有阅读的朋友可以点连接去阅读。本篇我们将分析事件分发机制主菜——ViewGroup的事件分发


一、事件的传递顺序

为什么说ViewGroup的事件分发是主菜呢?在解答这个问题之前,我们先看一看触摸事件是怎么到达View手中的:

  1. 触摸到手机屏幕后,手机的屏幕会将点击事件传递给Activity
  2. Activity将事件交给PhoneWindow(Activity的dispatchTouchEvent方法),PhoneWindow是Window的实现类
  3. PhoneWindow将事件交给DecorView(PhoneWindow的superDispatchTouchEvent方法),这个DecorView就是Activity的根布局,它实际上是一个FrameLayout
  4. DecorView将事件交给布局文件中的根布局,随后依次向下传递
  5. 最终传递到了View手中

通过上面的传递步骤,大家可以看到事件是经由多个ViewGroup最终传递到了View手中。我们知道ViewGroup是一个容器,里面装着子View,那么ViewGroup应该把事件交给哪个子View呢?这里的逻辑就要比View的事件分发复杂多了。

好的,废话不多说,我们开始进入正题


二、要提前知道的几个概念

我在阅读源码的过程中走了不少弯路,主要是有一些概念没有弄懂,所以为了防止大家在阅读的时候懵逼,我们在看源码之前,先了解几个概念


1.pointer指针的概念

在源码中,频繁的提到了指针这个概念,这在早期安卓版本中是没有的,那么,这个指针究竟是何方神圣呢?

我发现,pointer这个概念的出现和MotionEvent联系密切,于是我翻看了MotionEvent的源码,果然,在MotionEvent的类注释中,找到了对Pointer的描述,我对这些描述进行了翻译:

/**
 * Some devices can report multiple movement traces at the same time.  Multi-touch
 * screens emit one movement trace for each finger.  The individual fingers or
 * other objects that generate movement traces are referred to as <em>pointers</em>.
 * Motion events contain information about all of the pointers that are currently active
 * even if some of them have not moved since the last event was delivered.
 */
 一些设备可以同时报告多个运动轨迹。多点触摸屏为每个手指发射一个运动轨迹。
 生成运动轨迹的各个手指或其他对象被称为<em>指针</em>.
 运动事件包含关于当前活动的所有指针的信息,即使它们中的一些自从递送最后一个事件以来没有移动。
----------------------------------------------------------------------------------------------------
/**
 * Each pointer has a unique id that is assigned when it first goes down
 * (indicated by {@link #ACTION_DOWN} or {@link #ACTION_POINTER_DOWN}).  A pointer id
 * remains valid until the pointer eventually goes up (indicated by {@link #ACTION_UP}
 * or {@link #ACTION_POINTER_UP}) or when the gesture is canceled (indicated by
 * {@link #ACTION_CANCEL}).
 */
 每个指针都有一个唯一的id,当它第一次Down时分配。
 指针id保持有效,直到指针最终Up或手势被Cancel

----------------------------------------------------------------------------------------------------
/**
 * The order in which individual pointers appear within a motion event is undefined.
 * Thus the pointer index of a pointer can change from one event to the next but
 * the pointer id of a pointer is guaranteed to remain constant as long as the pointer
 * remains active.  Use the {@link #getPointerId(int)} method to obtain the
 * pointer id of a pointer to track it across all subsequent motion events in a gesture.
 * Then for successive motion events, use the {@link #findPointerIndex(int)} method
 * to obtain the pointer index for a given pointer id in that motion event.
 */
 每个指针在运动事件中出现的顺序未定义。
 因此,从一个事件到下一个事件时,指针的索引会发生改变,但是指针id保证保持恒定,只要指针保持活动。
 使用{@link #getPointerId(int)}方法获取指针的id,以便在手势中的所有后续运动事件中跟踪它。
 然后对于连续的运动事件,使用{@link #findPointerIndex(int)}方法获得该运动事件中给定指针id的指针索引。

通过官方的描述,我们可以知道:指针是随着多点触摸技术出现的概念,实际使用手机时,会出现同时多点触摸到手机屏的情况,所以每个触摸点就用指针来描述。早期的安卓源码之所以没有这个概念,我想应该是那时候还没有开发出支持多点触摸的屏幕


2.TouchTarget分发目标的数据结构

TouchTarget是ViewGroup的内部类,用途大家通过名字也应该能知道,这个类是对事件分发目标的封装,我们在这里主要了解一下这个类封装的数据结构

我们看一下TouchTarget的源码,在这里我就直接给大家截图出来了


好,我们可以看到,TouchTarget里封装着目标View以及指针等等。

值得我们注意的是我用红圈圈住的地方,一个TouchTarget肚子里装着另一个TouchTarget的引用,并且起名叫next~看到这里大家是否想起了什么?

没错,就是链表数据结构!所有TouchTarget被串成串,组成了一个分发目标列表,在分发的时候会将这个列表遍历,然后依次分发下去。相信大家了解了这一点之后,在下面源码中看到遍历TouchTarget的时候就不会蒙了


3、dispatchTransformedTouchEvent方法


提前对事件分发机制有了解的朋友应该知道,在ViewGroup的逻辑中,会去调用子View的dispatchTouchEvent方法,或者调用super.dispatchTouchEvent()方法。但是在API-24的源码中,并没有发现直接调用dispatchTouchEvent。在这里,dispatchTransformedTouchEvent方法中,进行了一系列的逻辑判断,并对dispatchTouchEvent方法进行了相应的调用,我们来简单看一下这个方法,感兴趣的朋友可以看一下源码以及我的注释;如果感觉看源码有点晕,可以跳过源码直接看下面的分析~

/**
* 将运动事件转换为指定子控件的坐标空间,过滤掉不相关的指针,并在必要时覆盖其操作。
* 如果child为null,则假设MotionEvent将发送到此ViewGroup。
*/
private boo
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值