View 事件分发
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事件分发的一些总结。
- 正常情况下一个事件序列只能够被一个View拦截。这一条可以参考(2),因为一旦一个元素拦截了某此事件,那么同一个事件序列内的所有事件都会直接交给它处理,因此同一个事件序列中的事件不能分别由两个View同时处理,但是通过特殊手段可以做到,比如一个View将本该 自己处理的事件通过 onTouchEvent强行传递给其他View处理。
- 某个View一旦决定拦截,那么这一个事件序列都只能由它来处理〈如果事件序列能够传递给它的话),并且它的onInterceptTouchEvent不会再被调用。这条也很好理解,就是说当一个View决定拦截一个事件后,那么系统会把同一个事件序列内的其他方法都直接交给它来处理,因此就不用再调用这个View的onJnterceptTouchEvent去询问它是否要拦截了。
- 某个View一旦开始处理事件,如果它不消耗ACTION_DOWN事件(onTouchEvent返回了false), 那么同一事件序列中的其他事件都不会再交给它来处理,并且事件将重新交由它的父元素去处理,即父元素的onTouchEvent会被调用。意思就是事件一旦交给一个View处理, 那么它就必须消耗掉,否则同一事件序列中剩下的事件就不再交给它来处理了,这就好比上级交给程序员一件事,如果这件事没有处理好,短期内上级就不敢再把事情交给这个程序员做了,二者是类似的道理。
- 如果View不消耗除ACTION_DOWN以外的其他事件, 那么这个点击事件会消失,此时父元素的onTouchEvent并不会被调用,并且当前View可以持续收到后续的事件,最终这些消失的点击事件会传递给Activity处理。
- ViewGroup 默认不拦截任何事件。Android源码中ViewGroup的onInterceptTouchEvent方法默认 返回false。
- View没有onInterceptTouchEvent方法,一旦有点击事件传递给它,那么它的onTouchEvent方法就会被 调用。
- View的onTouchEvent 默认 都会消耗事件(返回true), 除非它是不可点击的(clickable和longClickable同时为false)。View的longClickable属性默认都为人alse,clickable属性要分情况,比如Button的clickable属性默认为true, 而TextView的clickable属性默认为false。
- View的enable属性不影响onTouchEvent的默认 返回值。哪怕一个View是disable状态的,只要它的clickable或者 longClickable有一个为tue,那么它的onTouchEvent就返回true。
- onClick会发生的前提是当前View是可点击的,并且它收到了down和up的事件。
- 事件传递过程是由外向内的,即事件总是先传递给父元素,然后再由父元素分发给子View,通过requestDisallowInterceptTouchEvent方法可以在子元素中干预父元素的事件分发过程,但是ACTION_DOWN事件除外。
View 事件分发的更多相关文章
- Atitit View事件分发机制
1. Atitit View事件分发机制 1. Atitit View事件分发机制1 1.1. 三个关键方法 dispatchTouchEvent onInterceptTouchEvent onTo ...
- Android View框架总结(七)View事件分发机制
请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52282833 View布局告一段落,从本篇开始View事件相关分析, ...
- Android View事件分发-从源码分析
View事件分发-从源码分析 学习自 <Android开发艺术探索> https://blog.csdn.net/qian520ao/article/details/78555397?lo ...
- Android面试必问!View 事件分发机制,看这一篇就够了!
在 Android 开发当中,View 的事件分发机制是一块很重要的知识.不仅在开发当中经常需要用到,面试的时候也经常被问到. 如果你在面试的时候,能把这块讲清楚,对于校招生或者实习生来说,算是一块不 ...
- Android View 事件分发机制 源码解析 (上)
一直想写事件分发机制的文章,不管咋样,也得自己研究下事件分发的源码,写出心得~ 首先我们先写个简单的例子来测试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个My ...
- android View事件分发机制结论
原始博客有对源码的分析:http://blog.csdn.net/lmj623565791/article/details/39102591 结论:1.view事件的分发流程: dispatchTou ...
- View事件分发机制
所谓的事件分发,其实就是对MotionEvent事件的分发过程,即当一个MotionEvent产生后,系统需要把这个事件传递给一个具体的View,而这个传递的过程就是分发过程. 点击事件的分发由3个方 ...
- Android View 事件分发机制详解
想必很多android开发者都遇到过手势冲突的情况,我们一般都是通过内部拦截和外部拦截法解决此类问题.要想搞明白原理就必须了解View的分发机制.在此之前我们先来了解一下以下三个非常重要的方法: di ...
- 自定义控件(视图)2期笔记10:自定义视图之View事件分发机制("瀑布流"的案例)
1. Touch事件的传递: 图解Touch事件的传递,如下: 当我们点击子View 02内部的Button控件时候,我们就触发了Touch事件. • 这个Touch事件首先传递给了顶级父View ...
随机推荐
- k8s role
转 https://blog.qikqiak.com/post/add-authorization-for-kubernetes-dashboard/ 另外还可以参考这个 https://mrit ...
- Excel:函数中的万金油:INDEX+SMALL+IF+ROW
很多人在Excel中用函数公式做查询的时候,都必然会遇到的一个大问题,那就是一对多的查找/查询公式应该怎么写?大多数人都是从VLOOKUP.INDEX+MATCH中入门的,纵然你把全部的多条件查找 ...
- Angular 下的 directive (part 2)
ngCloak ngCloak指令被使用在,阻止angular模板从浏览器加载的时候出现闪烁的时候.使用它可以避免闪烁问题的出现. 该指令可以应用于<body>元素,但首选使用多个ng ...
- 使用js获取浏览器地址栏里的参数
用JS获取地址栏参数的方法(超级简单) 方法一:采用正则表达式获取地址栏参数:( 强烈推荐,既实用又方便!) function GetQueryString(name) { var reg = new ...
- ARMCC和GCC编译ARM代码的软浮点和硬浮点问题【转】
转自:https://blog.csdn.net/hunanchenxingyu/article/details/47003279 本文介绍了ARM代码编译时的软浮点(soft-float)和硬浮点( ...
- Linux进程托管与守护进程设置
引言 在上一篇<Linux启动之旅>中,我们了解了Linux启动过程,在该过程的最后一步,init进程拉起/etc/init.d/rcN.d/目录下指定的守护进程(daemon).假若自定 ...
- pop3设置
- 002_更新Nginx证书
全球可信并且唯一免费的HTTPS(SSL)证书颁发机构:StartSSL 1.自行颁发不受浏览器信任的SSL证书: HTTPS的SSL证书可以自行颁发,Linux下的颁发步骤如下: openssl g ...
- Jenkins与代码上线解决方案
Jenkins是一个用Java编写的开源的持续集成工具.在与Oracle发生争执后,项目从Hudson项目独立. Jenkins提供了软件开发的持续集成服务.它运行在Servlet容器中(例如Apac ...
- java虚拟机规范(se8)——java虚拟机结构(五)
2.10 异常 java虚拟机中的异常用Throwable类或者它的子类的实例来表示.抛出一个异常会导致立即非本地(an inmediate nolocal)的控制转移,从发生异常的地方跳到处理异常的 ...