View 事件分发

学习自

《Android开发艺术探索》

官方文档-MotionEvent

事件分发机制漫谈

View的事件分发机制,使我们了解View的工作原理继而学习如何自定义View的基础,尽管这些知识比较理论,但是还是很有必要了解其原理的,知其然不知其所以然是不可取的。

MotionEvent重提

我们在之前已经提到了MotionEvent对象也多少有些应用,但是并没有对其太过关注,而MotionEvent正式View事件分发机制的核心,我们有必要重新认识一下它,我们来看一下权威的官方文档。

Object used to report movement (mouse, pen, finger, trackball) events.Motion events may hold either absolute or relative movements and other data,depending on the type of device.

MotionEvent是被用来报道移动动作(鼠标,笔,手指,轨迹球)事件的对象。此对象可以基于设备类型持有绝对或相对的移动动作的数据和其他有关的数据。

通过官方文档了到了MotionEvent中存储的就是我们的 触屏 的信息,而Android对事件的处理正是对我们与设备的手势的交互的相应,View的事件的处理就是围绕着MotionEvent来展开的。

三个重要的方法

View事件的分发机制就是对MotionEvent的分发,最终将其传递给一个具体的View,这就是View事件的分发过程。在这个过程中有3个很重要的方法,接下来一起来看一看。

再看这三个方法之前我们需要先来了解一个概念----事件序列

事件序列指的是,从手指按下屏幕开始到手指离开屏幕期间所产生的事件,事件序列的第一个事件是 __down __最后一个事件是 up

dispatchTouchEvent

下面是此方法的方法签名,此方法的作用是将MotionEvent分发给目标View,其返回值代表的是,处理MotionEvent事件的是否是当前View.

public boolean dispatchTouchEvent(MotionEvent event)

onInterceptTouchEvent

此方法会在 dispatchTouchEvent 方法中调用,此方法的作用就是过滤掉那些不符合胃口的MotionEvent. 返回值是否拦截当前事件。如果此方法返回为 ture 那么在同一事件序列中该方法不会被再次调用。

public boolean onInterceptTouchEvent(MotionEvent ev)

onTouchEvent

此方法用来处理触屏的MotionEvent,如果返回ture表示MotionEvent已经被处理,否则反之。

public boolean onTouchEvent(MotionEvent event)

调用流程

当一个MotionEvent产生时,顶级的 ViewGroup的 dispatchTouchEvent 方法将会被调用,如果此时 onInterceptTouchEvent 方法返回为 ture 那么表示拦截当前的事件,此事件将会交给ViewGroup本身去执行,如果返回 false 那么事件会继续传递给 子View ,如此往复直到事件被处理。

OnTouchListener

如果一个View设置了OnTouchListener事件那么这时候需要注意了,如果返回为 ture 则不会调用 onTouchEvent 方法,因为onClick事件是在onTouchEvent方法中调用的所以,如果此时设置 onClick事件,onClick事件是不会执行的。由此可见onClick事件位于事件分发的末端部位。

一个特殊的情况

当一个事件产生的时候,是按照以下的顺序进行传递的: Activity->Window->View. 当顶级的View即ViewGroup接收到事件后,会向子View进行分发,如果子View拒绝对事件进行处理的话,那么事件就会返回值父View进行处理,要是有的View都不对事件进行处理的话,那么这时候事件就会重新返回给Activity处理 ,即Activity的onTouchEvent方法将会被调用。

归纳

下面是《Android开发艺术探索》的作者-任玉刚老师对View事件分发的一些总结。

  1. 正常情况下一个事件序列只能够被一个View拦截。这一条可以参考(2),因为一旦一个元素拦截了某此事件,那么同一个事件序列内的所有事件都会直接交给它处理,因此同一个事件序列中的事件不能分别由两个View同时处理,但是通过特殊手段可以做到,比如一个View将本该 自己处理的事件通过 onTouchEvent强行传递给其他View处理。
  2. 某个View一旦决定拦截,那么这一个事件序列都只能由它来处理〈如果事件序列能够传递给它的话),并且它的onInterceptTouchEvent不会再被调用。这条也很好理解,就是说当一个View决定拦截一个事件后,那么系统会把同一个事件序列内的其他方法都直接交给它来处理,因此就不用再调用这个View的onJnterceptTouchEvent去询问它是否要拦截了。
  3. 某个View一旦开始处理事件,如果它不消耗ACTION_DOWN事件(onTouchEvent返回了false), 那么同一事件序列中的其他事件都不会再交给它来处理,并且事件将重新交由它的父元素去处理,即父元素的onTouchEvent会被调用。意思就是事件一旦交给一个View处理, 那么它就必须消耗掉,否则同一事件序列中剩下的事件就不再交给它来处理了,这就好比上级交给程序员一件事,如果这件事没有处理好,短期内上级就不敢再把事情交给这个程序员做了,二者是类似的道理。
  4. 如果View不消耗除ACTION_DOWN以外的其他事件, 那么这个点击事件会消失,此时父元素的onTouchEvent并不会被调用,并且当前View可以持续收到后续的事件,最终这些消失的点击事件会传递给Activity处理。
  5. ViewGroup 默认不拦截任何事件。Android源码中ViewGroup的onInterceptTouchEvent方法默认 返回false。
  6. View没有onInterceptTouchEvent方法,一旦有点击事件传递给它,那么它的onTouchEvent方法就会被 调用。
  7. View的onTouchEvent 默认 都会消耗事件(返回true), 除非它是不可点击的(clickable和longClickable同时为false)。View的longClickable属性默认都为人alse,clickable属性要分情况,比如Button的clickable属性默认为true, 而TextView的clickable属性默认为false。
  8. View的enable属性不影响onTouchEvent的默认 返回值。哪怕一个View是disable状态的,只要它的clickable或者 longClickable有一个为tue,那么它的onTouchEvent就返回true。
  9. onClick会发生的前提是当前View是可点击的,并且它收到了down和up的事件。
  10. 事件传递过程是由外向内的,即事件总是先传递给父元素,然后再由父元素分发给子View,通过requestDisallowInterceptTouchEvent方法可以在子元素中干预父元素的事件分发过程,但是ACTION_DOWN事件除外。

View 事件分发的更多相关文章

  1. Atitit View事件分发机制

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

  2. Android View框架总结(七)View事件分发机制

    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52282833 View布局告一段落,从本篇开始View事件相关分析, ...

  3. Android View事件分发-从源码分析

    View事件分发-从源码分析 学习自 <Android开发艺术探索> https://blog.csdn.net/qian520ao/article/details/78555397?lo ...

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

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

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

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

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

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

  7. View事件分发机制

    所谓的事件分发,其实就是对MotionEvent事件的分发过程,即当一个MotionEvent产生后,系统需要把这个事件传递给一个具体的View,而这个传递的过程就是分发过程. 点击事件的分发由3个方 ...

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

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

  9. 自定义控件(视图)2期笔记10:自定义视图之View事件分发机制("瀑布流"的案例)

    1. Touch事件的传递:   图解Touch事件的传递,如下: 当我们点击子View 02内部的Button控件时候,我们就触发了Touch事件. • 这个Touch事件首先传递给了顶级父View ...

随机推荐

  1. C#访问和操作MYSQL数据库

    这里介绍下比较简单的方式,引用MySql.Data.dll然后添加一个MySqlHelper类来对MySql数据库进行访问和操作. 1.将MySql.Data.dll引用到你的项目中 下载地址:MyS ...

  2. timer.Interval用法简介

    这个东东呢是我在做windows服务的时候碰到的,总结了一下她的用法,如下: 一.指定时间间隔 写一个每隔一分钟就执行一次的吧 public partial class PSJCService : S ...

  3. Python字符串,整型,浮点数相互转化

    Python字符串,整型,浮点数相互转化 觉得有用的话,欢迎一起讨论相互学习~Follow Me int(str) 函数将符合整数的规范的字符串转换成int型 float(str) 函数将符合浮点数的 ...

  4. 如何通过卡面标识区分SD卡的速度等级

    现在很多设备都可以插存储卡,而比较流行的就是SD(Secure Digital Memory Card)卡和Micro SD(原名TF,Trans-flash Card )卡,这两种卡主要就是尺寸不同 ...

  5. Linux 定时器应用【转】

    Linux 定时器应用 实验目的 阅读 Linux 相关源代码,学习 Linux 系统中的时钟和定时器原理,即,ITIMER_REAL实时计数,ITIMER_VIRTUAL 统计进程在用户模式执行的时 ...

  6. [SDOI2009]HH去散步 「矩阵乘法计数」

    计数问题也许可以转化为矩阵乘法形式 比如若该题没有不能在一条边上重复走的条件限制,那么直接将邻接矩阵转化为矩阵乘法即可 故 矩阵乘法计数 对于计数问题,若可以将 \(n\) 个点表示成 \(n \ti ...

  7. Project Euler Problem1

    Multiples of 3 and 5 Problem 1 If we list all the natural numbers below 10 that are multiples of 3 o ...

  8. Python_oldboy_自动化运维之路_面向对象(十)

    面向对象编程 OOP编程是利用“类”和“对象”来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向 ...

  9. nodejs抓取别人家的页面的始末

    内容:分析并获取页面调取数据的API(接口),并跨域获取数据保存在文档中(nodejs做代理-CORS) 事由以及动机 2015年9月份全国研究生数学建模竞赛的F题,旅游线路规划问题.其中需要自己去查 ...

  10. vue.js 解决空格报错!!!

    当我们初入vue.js的时候.使用cli脚手架快速创建项目的时候: 如果语法格式错误(这里主要指的是:空格多少引起的问题)!! 找到  webpack.base.config.js文件注释掉下面的东西 ...