引言

  前面的文章介绍了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事件分发机制的更多相关文章

  1. Android View 事件分发机制 源码解析 (上)

    一直想写事件分发机制的文章,不管咋样,也得自己研究下事件分发的源码,写出心得~ 首先我们先写个简单的例子来测试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个My ...

  2. android view事件分发机制

    首先我们先写个简单的例子来测试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个MyButton继承Button,然后把跟事件传播有关的方法进行复写,然后添加上日志 ...

  3. Android View 事件分发机制 源代码解析 (上)

    一直想写事件分发机制的文章,无论咋样,也得自己研究下事件分发的源代码.写出心得~ 首先我们先写个简单的样例来測试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个M ...

  4. Android View 事件分发机制详解

    想必很多android开发者都遇到过手势冲突的情况,我们一般都是通过内部拦截和外部拦截法解决此类问题.要想搞明白原理就必须了解View的分发机制.在此之前我们先来了解一下以下三个非常重要的方法: di ...

  5. android View事件分发机制结论

    原始博客有对源码的分析:http://blog.csdn.net/lmj623565791/article/details/39102591 结论:1.view事件的分发流程: dispatchTou ...

  6. Android之事件分发机制

    本文主要包括以下内容 view的事件分发 viewGroup的事件分发 首先来看两张图 在执行touch事件时 首先执行dispatchTouchEvent方法,执行事件分发. 再执行onInterc ...

  7. Android面试必问!View 事件分发机制,看这一篇就够了!

    在 Android 开发当中,View 的事件分发机制是一块很重要的知识.不仅在开发当中经常需要用到,面试的时候也经常被问到. 如果你在面试的时候,能把这块讲清楚,对于校招生或者实习生来说,算是一块不 ...

  8. Atitit View事件分发机制

    1. Atitit View事件分发机制 1. Atitit View事件分发机制1 1.1. 三个关键方法 dispatchTouchEvent onInterceptTouchEvent onTo ...

  9. android的事件分发机制理解

    android的事件分发机制理解 1.事件触发主要涉及到哪些层面的哪些函数(个人理解的顺序,可能在某一层会一次回调其它函数) activity中的dispatchTouchEvent .layout中 ...

随机推荐

  1. 如何使用 Flexbox 和 CSS Grid,实现高效布局

    CSS 浮动属性一直是网站上排列元素的主要方法之一,但是当实现复杂布局时,这种方法不总是那么理想.幸运的是,在现代网页设计时代,使用 Flexbox 和 CSS Grid 来对齐元素,变得相对容易起来 ...

  2. 题目1454:Piggy-Bank(完全背包问题)

    题目链接:http://ac.jobdu.com/problem.php?pid=1454 详解链接:https://github.com/zpfbuaa/JobduInCPlusPlus 参考代码: ...

  3. javascript 闭包学习

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域 ...

  4. PtH(hash传递攻击)原理探秘

    背景知识 Windows 横向渗透的两种方式 1.hash传递攻击,通过传递NTLM-Hash,登录机器,简称PtH: 2.ticket传递攻击,通过传递kerberos的ticket,登录机器,简称 ...

  5. hdu2222 Keywords Search【AC自动机】

    Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others ...

  6. pcl学习笔记(二):点云类型

    不同的点云类型 前面所说的,pcl::PointCloud包含一个域,它作为点的容器,这个域是PointT类型的,这个域是PointT类型的是pcl::PointCloud类的模板参数,定义了点云的存 ...

  7. python数据结构之哈希表

    哈希表(Hash table) 众所周知,HashMap是一个用于存储Key-Value键值对的集合,每一个键值对也叫做Entry.这些个键值对(Entry)分散存储在一个数组当中,这个数组就是Has ...

  8. .windows安装使用这些偏底层的Python扩展太

    .windows安装使用这些偏底层的Python扩展太不爽了,怎么彻底解决 error: Unable to find vcvarsall.bat呢? 1.不要按网上说的,安装MinGW,然后在“.. ...

  9. vs code 设置工作区背景图片方法

    1.扩展--安装background 2.文件--首选项--设置--在settings.josn中编辑--右侧用户设置添加 "background.useFront": false ...

  10. 【xargs -i】复制文件夹中前100个文件

    复制前一万个文件到 tmp 下 |xargs -i cp {} /tmp 复制后一万个文件到 tmp 下 |xargs -i cp {} /tmp 查看linux下文件夹文件数目 ls -l |gre ...