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. golang(01) linux环境搭建和编码

    1 在自己的工作目录下建立一个goproject文件夹 /home/secondtonone/goproject 2 在文件夹下建立如下三个文件 bin pkg srcbin 保存执行go insta ...

  2. 使用pandas导入csv文件到MySQL

    之前尝试过用命令行来解决csv文件导入到MySQL这个问题,没想到一直没有成功.之后会继续更新的吧,现在先用pandas来解决这个问题,虽然会复杂一点,但至少能用. 例子是导入movielens的ra ...

  3. 20181111 Quartz(慕课网)

    Quartz体系结构 三个核心概念 调度器 任务 触发器 重要组成 Job JobBuilder JobDetail JobStore Trigger TriggerBuilder ThreadPoo ...

  4. Python基础数据类型-函数传参详解

    Python基础数据类型-函数传参详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.位置参数 #!/usr/bin/env python #_*_coding:utf-8_* ...

  5. 卸载并安装指定版本Angular CLI

    1.卸载之前的版本 npm uninstall -g @angular/cli 2.清除缓存,确保卸载干净 npm cache clean 3.检查是否卸载干净 输入命令 ng -v 若显示comma ...

  6. c#的委托用法delegate

  7. Spring RedisTemplate操作-List操作(4)

    @Autowired @Resource(name="redisTemplate") private RedisTemplate<String, String> rt; ...

  8. 关于升级程序版本时version与build修改的问题

    CHENYILONG Blog 关于升级程序版本时version与build修改的问题 #问题#从V1.0升级到V1.0.1.version是一定要改的,那么build需要修改吗? #解答#一般习惯上 ...

  9. 【ORACLE】oracl基本操作笔记

    1.用命令导入导出表 C:\Users\xiang>imp bjlims/bjlims@orcl file="c:\tjlims.dmp" full=y C:\Users\x ...

  10. Redis知识点总结

    1.单线程 单线程模型来处理客户端的请求,对读写等事件的相应是通过对epoll函数的包装来做到的,Redis的实际处理速度完全依靠主线程的执行效率. Epoll是Linux内核为处理大批量文件描述符而 ...