浅谈Android View事件分发机制
引言
前面的文章介绍了View的基础知识和View的滑动,今天我们来介绍View的另一个核心知识,View的事件分发机制。
点击事件的传递规则
所谓的点击事件的分发机制,其实就是对MotionEvent事件的分发过程,当一个MotionEvent产生以后,系统需要把这个事件传递给一个具体的View,这个传递的过程就是分发过程。点击事件的分发主要由三个很重要的方法来共同完成的,它们是:dispatchTouchEvent、onInterceptTouchEvent和OnTouchEvent。下面我们一一介绍这些方法。
public boolean dispatchTouchEvent(MotionEvent event)
用来进行事件的分发。如果事件能够传递给当前的View,这个方法是一定会被调用的,返回结果受到当前View的OnTouchEvent和下级View的dispatchTouchEvent方法的影响,返回值表示是否消耗当前事件(true消耗)。
public boolean onInterceptTouchEvent(MotionEvent ev)
这个方法是在上面一个方法的内部调用的,用来判断是否拦截某个事件。如果当前View拦截了某一个事件,那么在同一个事件序列中,此方法不会被再次调用,返回结果表示是否拦截当前的事件。
public boolean onTouchEvent(MotionEvent event)
在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一个事件序列中,当前View无法再次接收到事件。
那么上面3个方法到底有什么区别呢?下面我们用一段伪代码来表述:

上面的代码已经很清晰的表达了3者之间的关系,通过上面的代码我们大致可以知道点击事件的传递规则:对于一个根ViewGroup来说,点击事件产生后,首先会传递给它,这时候它的dispatchTouchEvent就会被调用。这个时候会有两种情况:
第一种情况:如果这个ViewGroup的onInterceptTouchEvent方法返回true就表示它需要拦截当前事件,接着事件就会交给这个ViewGroup处理,就是它的onTouchEvent方法会被调用。
第二种情况:如果这个ViewGroup的onInterceptTouchEvent方法返回false就表示它不需要拦截当前事件,这时这个事件就会继续传递给它的子元素,接着子元素的dispatchTouchEvent就会被调用,如此反复直到事件被最终处理。
注意点:
当一个View需要处理事件时,如果设置了OnTouchListener,那么OnTouchListener中的onTouch方法会被调用。这时候事件如何处理还是需要看onTouch方法的返回值。这时候又分成两种情况:
第一种情况:如果onTouch方法返回false,那么当前View的onTouchEvent方法会被调用;
第二种情况:如果onTouch方法返回true,那么当前View的onTouchEvent方法不会被调用,处理逻辑会在OnTouch方法中完成。
通过这个逻辑我们知道,给View设置的OnTouchListener优先级要比onTouchEvent方法要高。在onTouchEvent方法中,如果我们设置有OnClickListener,那么它的onClick方法会被调用。我们可以看出平时我们常用的OnClickListener其优先级最低,处于事件传递的末端。
简单的总结归纳
当一个点击事件产生以后,它的传递过程遵循如下顺序Activity-->Window-->View。即事件总要先传递给Activity,然后在传递给Window,最后Window在传递给顶级的View。顶级的View接收到事件后,就会按照事件分发机制去分发事件。
关于事件传递机制,这里给出一些结论,根据这些结论可以更好的理解整个事件传递机制。
1、同一个事件序列是指从手指触摸屏幕的那一刻起,到手指离开屏幕的那一刻结束,在这个过程中所产生的一系列事件,这个事件序列以down事件开始,中间含有数量不定的move事件,最后以up事件结束。
2、某一个View一旦决定拦截,那么这一事件序列都只能由他来处理(如果事件序列可以传递给它),并且它的onInterceptTouchEvent不会再被调用。我们可以这样理解这段描述,就是当一个View决定拦截一个事件后,系统会把同一个事件序列中的其他都事件都直接交给他处理,不需要再调用View的onInterceptTouchEvent去询问是否需要拦截。
3、正常情况下,一个事件序列只能被一个View拦截且消耗。原因第二条已经说的很清楚了。
4、某个View一旦开始处理事件,如果它不消耗ACTION_DOWN事件(onTouchEvent方法返回false),那么同一个事件序列中的其他事件都不会再交给他处理,并且事件将重新交给它的父元素去处理,即父元素的onTouchEvent方法会被调用。意思就是:事件一旦交给一个View去处理,那么它就必须消耗掉,否则同一个事件序列中剩下的事件不会再交给它处理。
5、如果View不消耗除ACTION_DOWN以外的其他事件,那么这个点击事件会消失,此时父元素的onTouchEvent并不会被调用,并且当前View可以持续接收到后续的事件,最终这些消失的点击事件会传递给Activity处理。
6、ViewGroup默认不会拦截任何事件,Android源码中ViewGroup中的onInterceptTouchEvent方法默认方法false。
7、View没有dispatchTouchEvent方法,一旦有点击事件传递给它,那么它的onTouchEvent方法会被调用。
8、View的onTouchEvent默认会消耗事件(返回true),除非它是不可点击的(clickable和longClickable都是false)。View的longClickable属性默认都是false,click属性要分情况,Button的clickable属性默认是true,TextView的clickable默认是false。不过设置OnClickListener会将clickable设置为true。
9、onClick会发生的前提是当前View是可点击的,并且受到down和up的事件。
11、事件传递的过程总是由外向内的,事件总是先传递给父元素,然后再有父元素分发给子View。通过requestDisallowInterceptTouchEvent方法可以在子元素中干预父元素的事件分发过程,但是ACTION_DOWN事件除外。
下篇文章我们来从源码的角度来解析View的事件分发机制。
浅谈Android View事件分发机制的更多相关文章
- Android View 事件分发机制 源码解析 (上)
一直想写事件分发机制的文章,不管咋样,也得自己研究下事件分发的源码,写出心得~ 首先我们先写个简单的例子来测试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个My ...
- android view事件分发机制
首先我们先写个简单的例子来测试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个MyButton继承Button,然后把跟事件传播有关的方法进行复写,然后添加上日志 ...
- Android View 事件分发机制 源代码解析 (上)
一直想写事件分发机制的文章,无论咋样,也得自己研究下事件分发的源代码.写出心得~ 首先我们先写个简单的样例来測试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个M ...
- Android View 事件分发机制详解
想必很多android开发者都遇到过手势冲突的情况,我们一般都是通过内部拦截和外部拦截法解决此类问题.要想搞明白原理就必须了解View的分发机制.在此之前我们先来了解一下以下三个非常重要的方法: di ...
- android View事件分发机制结论
原始博客有对源码的分析:http://blog.csdn.net/lmj623565791/article/details/39102591 结论:1.view事件的分发流程: dispatchTou ...
- Android之事件分发机制
本文主要包括以下内容 view的事件分发 viewGroup的事件分发 首先来看两张图 在执行touch事件时 首先执行dispatchTouchEvent方法,执行事件分发. 再执行onInterc ...
- Android面试必问!View 事件分发机制,看这一篇就够了!
在 Android 开发当中,View 的事件分发机制是一块很重要的知识.不仅在开发当中经常需要用到,面试的时候也经常被问到. 如果你在面试的时候,能把这块讲清楚,对于校招生或者实习生来说,算是一块不 ...
- Atitit View事件分发机制
1. Atitit View事件分发机制 1. Atitit View事件分发机制1 1.1. 三个关键方法 dispatchTouchEvent onInterceptTouchEvent onTo ...
- android的事件分发机制理解
android的事件分发机制理解 1.事件触发主要涉及到哪些层面的哪些函数(个人理解的顺序,可能在某一层会一次回调其它函数) activity中的dispatchTouchEvent .layout中 ...
随机推荐
- jQuery事件处理(四)
看了几天,决定整理一下jQuery事件处理的整体设计思路 1.通过add方法给选中的元素注册事件处理程序(通过缓存系统将事件储存到cache,而不是绑定到元素上) a.在存储之前,会为事件处理程序增加 ...
- 对Array进行排序(按字母顺序)
通过使用java.utils.Arrays.sort()和String.CASE_INSENSITIVE_OREDR,可以很容易的对结果进行排序(按字母顺序): String[] array = { ...
- Sencha Touch 实战开发培训 视频教程 第二期 第三节
2014.4.11晚上8:10分开课. 本节课耗时一小时以上. 本期培训一共八节,前两节免费,后面的课程需要付费才可以观看. 本节内容: 本地储存.扩展按钮控件.微博分享 实现 ...
- ftp主动与被动模式详解
FTP是仅基于TCP的服务,不支持UDP.与众不同的是FTP使用2个端口,一个数据端口和一个命令端口(也可叫做控制端口).通常来说这两个端口是21(命令端口)和20(数据端口).但FTP工作方式的不同 ...
- docker 参数
-a, --attach=[] Attach to STDIN, STDOUT or STDERR 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项 --add-host= ...
- C语言如何产生随机数
1.基本函数 在C语言中取随机数所需要的函数是: int rand(void); void srand(unsigned int n); rand()函数和srand()函数被声明在头文件stdlib ...
- C# 队列(Queue)解决简单并发
日志例子: private static Queue<string> m_Message = new Queue<string>(); private static bool ...
- 第一个maven项目
1.新建maven project 注意:勾上create a new simple project 2.填写相关信息, Grounp id为大项目名字,Artifact id为小项目的名字.注意:P ...
- python3安装builtwith
>>> import builtwith Traceback (most recent call last): File , in <module> File excep ...
- ftok函数
ftok函数 系统建立IPC通讯(消息队列.信号量和共享内存)时必须指定一个ID值.通常情况下,该id值通过ftok函数得到. ftok原型 头文件: #include <sys/types.h ...