浅谈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中 ...
随机推荐
- 本版本延续MVC中的统一验证机制~续的这篇文章,本篇主要是对验证基类的扩展和改善(转)
本版本延续MVC中的统一验证机制~续的这篇文章,本篇主要是对验证基类的扩展和改善 namespace Web.Mvc.Extensions { #region 验证基类 /// <summary ...
- Android JSON语法解析示例
参考: http://www.open-open.com/lib/view/open1326376799874.html https://www.cnblogs.com/jycboy/p/json_x ...
- Android 查看system/bin目录下支持哪些命令?
C:\Users\yonghuming>adb shell "ls system/bin" >log acpiadbdamapp_processapp_process3 ...
- Installed .NET Framework 4.5 Ajax POST IIS hang
去年我已写过一篇关于安装.NET Framework 4.5后特定场景Ajax POST的挂起问题 => http://www.cnblogs.com/junchu25/archive/2012 ...
- ubuntu 14.04 升级到 16.04 问题总结
1. 需要的依赖关系未安装 The required dependency 'apt (>= 1.0.1ubuntu2.13)' is not installed. http://forum.u ...
- C99中的变长数组(VLA)
处理二维数组的函数有一处可能不太容易理解,数组的行可以在函数调用的时候传递,但是数组的列却只能被预置在函数内部.例如下面这样的定义: #define COLS 4 int sum3d(int ar[] ...
- 用js内置对象XMLHttpRequest 来用ajax
步骤: /* 用XMLHTTPRequest来进行ajax异步数据交交互*/ 主要有几个步骤: //1.创建XMLHTTPRequest对象 //最复杂的一步 if (window.XMLHttpRe ...
- vue之cli脚手架安装和webpack-simple模板项目生成
ue-cli 是一个官方发布 vue.js 项目脚手架,使用 vue-cli 可以快速创建 vue 项目. GitHub地址是:https://github.com/vuejs/vue-cli 一.安 ...
- js获取文件对象
- <input type=file>上传唯一控件
值得注意的是:当一个表单里面包含这个上传元素的时候,表单的enctype必须指定为multipart/form-data,method必须指定为post,浏览器才会认识并正确执行.但是还有一点,浏览器 ...