Android 的事件分发机制

本文详细解析了Android中的触控事件分发机制,包括事件如何从顶层Activity逐层传递到具体的View,并讨论了dispatchTouchEvent、onInterceptTouchEvent及onTouchEvent三个关键方法的作用与应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在我们通过屏幕与手机交互的时候,每一次点击、长按、移动等都是一个个事件。按照面向对象的思想,这些一个个事件都被封装成了MotionEvent。分发机制就是某一个事件从屏幕传递给app视图中的各个View,然后由其中的某个View来使用这一事件或者忽略这一事件,这整个过程的控制就是分发机制了。要注意的是,事件分发机制中,事件是按一个事件序列的形式分发给View的。这一序列由 ACTION_DOWN 开始,经过一系列 ACTION_MOVE 等事件,最后以 ACTION_UP 事件结束。这一个序列中的所有事件,要么被忽略,要么就只能有一个事件能使用。

每一个Activity内部都包含一个Window用来管理要显示的视图。而Window是一个抽象类,其具体实现是 PhoneWindow类。DecovrView作为PhoneWindow的一个内部类,实际管理着具体视图的显示。他是FrameLayout的子类,盛放着我们的标题栏和根视图。我们自己写的一些列View和ViewGroup都是由他来管理的。因此事件分发的时候,顶层的这些“大View”们实际上是不会对事件有任何操作的,他们只是把事件不断的向下递交,直到我们可以使用这些事件。

所以,事件自顶向下的传递过程应该是这样的:

Activity(不处理)-> 根View -> 一层一层ViewGroup(如果有的话) -> 子View

如果传递到最后我们的子View们没有处理这一事件怎么办呢?这时候就会原路返回,最终传递给Activity。只有当Activity也没有处理这一事件时,这一事件才会被丢弃。

Activity(不处理则丢弃) <- 根View <- 一层一层ViewGroup(如果有的话) <- 子View

具体在传递事件的时候,是由以下三个方法来控制的:

  • dispatchTouchEvent : 分发事件
  • onInterceptTouchEvent : 拦截事件
  • onTouchEvent : 消费事件

这三个方法有一个共同点,就是他们具体是否执行了自己的功能(分发、拦截、消费)完全由自己的返回值来确定,返回true就表示自己完成了自己的功能(分发、拦截、消费)。不同之处除了功能外,还有使用的场景。dispatchTouchEvent()和onTouchEvent()这两个方法,无论是Activity ViewGroup 还是View,都会被用到。而onInterceptTouchEvent()方法因为只是为了拦截事件,那么Activity和View一个在最顶层,一个在最底层,也就没必要使用了。因此在View 和 Activity中是没有onInterceptTouchEvent()方法的。

Android 的事件分发机制主要是 Touch 事件分发,有两个主角:ViewGroup 和 View。Activity的 Touch 事件事实上是调用它内部的 ViewGroup 的 Touch 事件,可以直接当成 ViewGroup 处理。View 在ViewGroup 内, ViewGroup 也可以在其他 ViewGroup 内, 这时候把内部的 ViewGroup当成 View 来分析。先分析 ViewGroup 的处理流程:首先得有个结构模型概念:ViewGroup 和 View 组成了一棵树形结构,最顶层为 Activity 的 ViewGroup,下面有若干的 ViewGroup 节点,每个节点之下又有若干的 ViewGroup 节点或者 View 节点,依次类推。如图:

当一个 Touch 事件(触摸事件为例)到达根节点,即 Acitivty 的 ViewGroup 时,它会依次下发,下发的过程是调用子 View(ViewGroup)的 dispatchTouchEvent 方法实现的。简单来说,就是ViewGroup 遍历它包含着的子 View,调用每个 View 的 dispatchTouchEvent 方法,而当子 View为 ViewGroup 时,又会通过调用 ViwGroup 的 dispatchTouchEvent 方法继续调用其内部的 View的 dispatchTouchEvent 方法。上述例子中的消息下发顺序是这样的:①-②-⑤-⑥-⑦-③-④。dispatchTouchEvent 方法只负责事件的分发,它拥有 boolean 类型的返回值,当返回为 true 时,顺序下发会中断。在上述例子中如果⑤的 dispatchTouchEvent 返回结果为 true,那么⑥-⑦-③-④将都接收不到本次 Touch 事件。

在传递过程中,只要有一个View主动去消费了第一个事件(ACTION_DOWN),那么ViewGroup会开始遍历自己的所有子View,找到需要接收到事件的View并将这个View保存起来,之后同一事件序列的其他事件都直接交给这个View来处理,无论是否找到,都会调用dispatchTransformedTouchEvent()方法,区别在于如果找到了, 那么在这个方法中传入的是那个View,否则就是null。只要找到了要接受事件的View,就会将他封装为一个target,保存起来,后续的其他事件(ACTION_MOVE, ACTION_UP)都由他来接收。

OnClick事件和OnLongClick事件是在onTouchEvent()中处理的,区别是OnClick在MotionEvent.ACTION_UP时,OnLongClick是在MotionEvent.ACTION_DOWN时。

如果onTouch()返回true, 则onTouchEvent不会执行,事件被消化不会继续传递。

 

补充:https://blog.youkuaiyun.com/morgan_xww/article/details/9372285,注意 其中activity没有onInterceptTouchEvent(MotionEvent ev)方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值