Android 事件机制简单总结

本文详细解释了Android中事件分发、拦截与消费的过程。从Activity到View的事件传递遵循特定的原则,即从外到内再由内向外。文中还介绍了关键类PhoneWindow和DecorView的作用,并展示了不同组件如何处理触摸事件。

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

事件分发

本文由其它几个博客简要及自己理解修改增加一些内容而成,还不完善,后续再完善。

原则:由外向内到最底层,再由内向外回传到最外层。

事件最Activity开始, 然后依次向下传递,最后传给View.大致如下:

Activity -> PhoneWindow -> DecorView -> ViewGroup -> ... -> View

如果没有任何View消费掉事件,那么这个事件会按照反方向回传,最终传回给Activity,如果最后 Activity 也没有处理,本次事件才会被抛弃。如何View消费掉事件,哪么回传true,告知上层。回传如下:

Activity <- PhoneWindow <- DecorView <- ViewGroup <- ... <- View

其实这就是一种责任链模式 如果自己能处理就拦截下来自己干,如果自己不能处理或者不确定就交给责任链中下一个对象。

自己可以直接拦截该事件,自己处理,也可以先询问(分发给)子View,如果子View需要就交给子View处理,如果子View不需要还能继续交给上层View处理。既保证了事件的有序性,又非常的灵活。


看到上面流程哪么DecorView和 PhoneWindow是做什么的?

要了解 PhoneWindow 是干啥的,首先要了解啥是 Window ,看官方说明:
Abstractbase class for a top-level window look and behavior policy. An instance of thisclass should be used as the top-level view added to the window manager. Itprovides standard UI policies such as a background, title area, default keyprocessing, etc.
简单来说,Window是一个抽象类,是所有视图的最顶层容器,视图的外观和行为都归他管,不论是背景显示,标题栏还是事件处理都是他管理的范畴,但它是抽象类不能直接使用。PhoneWindow 作为 Window 唯一实现类,Window的工作都是PhoneWindow来完成。
DecorView 是 PhoneWindow 的一个内部类,为PhoneWindow 服务的,除了自己的一些特性外,也负责消息的传递。屏幕上没View遮挡的部分会显示主题的颜色,标题的显示等存放在DecorView中。

由于我们无法直接操作 PhoneWindow 和 DecorView ,以下均省略了 PhoneWindow 和 DecorView。


事件分发、拦截与消费

 表示有该方法。

X 表示没有该方法。

类型 相关方法 Activity ViewGroup View
事件分发 dispatchTouchEvent
事件拦截 onInterceptTouchEvent X X
事件消费 onTouchEvent

这个三个方法均有一个 boolean(布尔) 类型的返回值,通过返回 true 和 false 来控制事件传递的流程。

PS: 从上表可以看到 Activity 和 View 都是没有事件拦截的,这是因为:

Activity 作为原始的事件分发者,如果 Activity 拦截了事件会导致整个屏幕都无法响应事件,这肯定不是我们想要的效果。

View最为事件传递的最末端,要么消费掉事件,要么不处理进行回传,根本没必要进行事件拦截。

public boolean dispatchTouchEvent(MotionEventevent) --分发事件

作用是用来进行事件的分发。一般在这个方法里必须写 returnsuper.dispatchTouchEvent 。如果不写super.dispatchTouchEvent,而直接改成return true 或者 false,则事件传递到这里时便终止了,既不会继续分发也不会回传给父元素。

public boolean onInterceptTouchEvent(MotionEvent event)--拦截事件

只有ViewGroup才有这个方法。View只有dispatchTouchEventonTouchEvent两个方法。因为View没有子View,所以不需要拦截事件。而ViewGroup里面可以包裹子View,所以通过onInterceptTouchEvent方法,ViewGroup可以实现拦截,拦截了的话,ViewGroup就不会把事件继续分发给子View了,也就是说在这个ViewGroup中的子View都不会响应到任何事件了。onInterceptTouchEvent 返回true时,表示ViewGroup会拦截事件。

public boolean onTouchEvent(MotionEvent event)--消费事件

onTouchEvent 返回true时,表示事件被消费掉了。一旦事件被消费掉了,其他父元素的onTouchEvent方法都不会被调用。如果没有人消耗事件,则最终当前Activity会消耗掉。则下次的MOVEUP事件都不会再传下去了。

注意:

  • 一般我们在自定义ViewGroup时不会拦截Down事件,因为一旦拦截了Down事件,那么后续的Move和Up事件都不会再传递下去到子元素了,事件以后都会只交给ViewGroup这里。

  • 一个Down事件分发完了之后,还有回传的过程。因为一个事件分发包括了Action_Down、Action_Move、Action_Up这几个动作。当手指触摸到屏幕的那一刻,首先分发Action_Down事件,事件分发完后还要回传回去,然后继续从头开始分发,执行下一个Aciton_Move操作,直到执行完Action_Up事件,整个事件分发过程便到此结束。


总结
一般来说
dispatchTouchEvent默认, ViewGroup消费事件时ViewGrouponInterceptTouchEvent(),return true,拦截事件,不会拦截Down事件,因为一旦拦截了Down事件,那么后续的MoveUp事件都不会再传递下去到子元素了,事件以后都会只交给ViewGroup这里ViewGrouponTouchEvent()return true, 处理事件。


另有:requestDisallowInterceptTouchEvent(true)请求父类不要拦截事件。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值