Android 事件拦截机制、事件分发机制简单分析

时间:2024-03-13 10:25:34

问题来了,为什么要了解事件拦截机制和分发机制?要解决什么问题?顾名思义就是要解决问题的,要解决的这个问题就是滑动冲突你要怎么解决?当然肯定要了解Android 事件分发,事件拦截机制了。

事件拦截机制

要了解触摸事件的拦截机制,首先要知道什么是触摸事件,其实很好的理解。就是打开APP页面,你用手指去触摸,当触摸产生后的系列事件。

通常情况下会产生2到3个事件,当手指按下,手指移动,手指离开,都分别有相关的事件触发。在Android 中为触摸事件封装了一个类叫做 MotionEvent,如果重写View里面的onTouchEvent()方法,你就会发现它的存在。

上图如下:
Android 事件拦截机制、事件分发机制简单分析

MotionEvent封装在里面方法
Android 事件拦截机制、事件分发机制简单分析

从上图可以看出来Motion封装各种方法,通过motion对象可以获取到触摸中的各种信息。

事件分发拦截机制的分析

当一个点击事件产生后,它传递过程的顺序如下:

Android 事件拦截机制、事件分发机制简单分析

每个Acivity都包含一个Window对象,在Android 中Window对象通常由PhoneWindow来实现。PhoneWindow将一个DecorView设置为整个应用窗口的跟View。DecorView作为窗口界面的顶层视图,封装了一些窗口操作的通用方法。那就是说DecorView将要显示的具体内容呈现在PhoneWindow上,这里面的所有View的监听事件,都通过WindowManagerService来进行接收,并通过Activity对象来回调相应的onClickListener。

要弄懂事件拦截分发机制其实很简单,我们可以来看一下生活中的例子都可以用来解释事件分发拦截机制。
比如:公司部门领导的沟通,各级省委领导的审批等。

首先,一般的android界面不可能只有1个VIEW,一般比较牛逼的应用1个界面都有N多个View来组成。所以这就涉及到View树的层级关系了,那就是说ViewGroup 里面有ViewGroup,ViewGroup里面有子View。

打个比方如图:

Android 事件拦截机制、事件分发机制简单分析

在上图,我们可以看到我们写XMLVIEW都是从外层根节点开始写到里面层的每个子VIEW。在Android中,加载XML文件是从根节点开始加载的所以,点击事件也是从顶层开始传到内层里面。哎,废话这么多,直接上分析图。。

Android 事件拦截机制、事件分发机制简单分析

上图就是简略的事件传递的过程,感觉还不是那么的具体,接下来再看更具体的分析图。

Android 事件拦截机制、事件分发机制简单分析

相信看完图就会明白,事件分发和事件拦截机制的简单原理和流程。后面更多的分析就需要结合源码来理解了。

事件分发机制一些小结

1)一个事件经过是指从手指接触屏幕的那一刻起,到手指离开屏幕的那一刻结束,在这个过程中所产生的一系列事件,这个事件序列以down事件开始,中间含有数量不定的move事件,最终以up事件结束。

2)正常情况下,一个事件只能被一个View拦截且消耗,因为一旦一个元素拦截了某事件,那么同一个事件序列内的所有事件都会直接交给它处理,因此同一个事件序列中的事件不能分别由两个View同事处理,但是通过特殊手段可以做到,比如一个view将本该自己处理的事件通过onTouchEvent强行传递给其他View处理。

3)某个View一旦决定拦截,那么这个事件序列都只能有他来处理(如果事件序列能够传递给它的的话),并且onInterceptTouchEvent不会再被调用。那就是说view决定拦截一个事件后,那么系统会把同一个事件序列内的其他方法都直接交给它处理,因此就不会再调用这个view的onInterceptTouchEvent去询问它是否要拦截。

4)某个View一旦开始处理事件,如果它不消耗ACTION_DOWN事件(onTouchEvent返回了false),那么同一个事件序列中其他事件都不会再交给它处理,并且事件将重新交由它的父元素去处理,那就是onTouchEvent会被调用。

5)如果View不消耗ACTION_DOWN意外的其他事件,那么这个点击事件会消失,此时父元素的onTouchEvent并不会被调用,并且当前View可以持续受到后续的事件,最终这些消失的点击事件会传递
给Activity处理

6)viewGroup默认不拦截任何事件。Android源码中ViewGroup的onInterceptTouchEvent方法默认返回false

7)View时没有onInterceptTouchEvent方法,一旦有点击事件传递给它,那么它onTouchEvent方法就会被调用。

8)View的onTouchEvent默认都会消耗事件,除非它是不可以点击的那就是clickable和同时为false。View的longClickable属性默认都是为false,clickable属性要分情况,比如Button的clickable属性默认为true,而且TextView的clickable属性默认为false。

9)View的enable属性不影响onTouchEvent的默认返回值,和clickable属性不一样。

10)事件传递过程是由外层传递到内层,父节点到子节点的传递。
(可以通过requestDisallowInterceptTouchEvent干预父元素的事件分发)

如果觉得我的文章对您有用,请点顶。您的支持将鼓励我继续码蛋!