引言

  前面的文章介绍了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. C#设计模式--工厂方法模式

    0.C#设计模式-简单工厂模式 设计模式: 工厂方法模式(Factory Method Pattern) 介绍:简单工厂模式是要在工厂类中通过数据来做个决策,在工厂类中的多个类中实例化出来其中一个要用 ...

  2. 原生js--事件类型

    1.表单事件: submit事件 reset事件 click事件 change事件 focus事件(不冒泡) (IE和ES5支持冒泡的focusin) blur事件(不冒泡) (IE和ES5支持冒泡的 ...

  3. Unity3D笔记十三 摄像机之间切换

    using UnityEngine; using System.Collections; public class _5_6 : MonoBehaviour { private GameObject ...

  4. div的最小宽高和最大宽高

    div的最小宽高和最大宽高很少使用但是很实用,今天敲代码,就遇到了,要在div里设置滚动条,众所周知,一般是设overflow-y:auto,但需要一个高度,只有div里的内容超过这个高度时,才会有滚 ...

  5. Equinox P2 介绍(一)Getting Start

    一直觉得 Equinox 的 P2 是个神秘的东西,常常使得 Eclipse 或 Equinox 表现出一些奇怪的行为,于是找来官方文档读一读,试图更好地理解与应用 Equinox . 官方文档很多, ...

  6. POJ 1061 - 青蛙的约会 - [exgcd求解一元线性同余方程]

    先上干货: 定理1: 如果d = gcd(a,b),则必能找到正的或负的整数k和l,使ax + by = d. (参考exgcd:http://www.cnblogs.com/dilthey/p/68 ...

  7. Django的quarySet

    models.py 代码 from django.db import models # Create your models here. class Author(models.Model): nam ...

  8. CodeForces - 950C Zebras 模拟变脑洞的天秀代码

    题意:给你一个01串,问其是否能拆成若干形如0101010的子串,若能,输出所有子串的0,1 的位置. 题解:一开是暴力,然后瞎找规律, 最后找到一种神奇的线性构造法:扫一遍字符串,若为0就一直竖着往 ...

  9. 第一个socket服务端程序

    第一个socket服务端程序 #include <stdio.h> #include <stdlib.h> #include <string.h> #include ...

  10. 疯狂java讲义 第三版 笔记

      java7新加特性: 0B010101  二进制数 int c=0B0111_1111;   数值中使用下划线分隔 switch 支持String类型   字符串常量放在常量池 String s0 ...