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 ...
随机推荐
- linux command ------ dmesg
驱动开发中使用函数 printk() 打印的信息可以通过 dmesg 查看 简介 ‘dmesg’命令显示linux内核的环形缓冲区信息,我们可以从中获得诸如系统架构.cpu.挂载的硬件,RAM等多个运 ...
- JS原型继承与类的继承
我们先看JS类的继承 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> &l ...
- vue+webpack开发(三)
上一篇博文讲了怎么使用路由,这次主要讲讲怎么编写一个vue组件 vue定义了一种“单文件组件”后缀为‘.vue’的文件,大概长这样子: <template> <div> < ...
- <meta content='IE=edge,chrome=1' http-equiv='X-UA-Compatible' />
代码一:<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> http-eq ...
- python---django中form组件(1)简单使用和字段了解
Django中的Form组件功能: 1.对用户请求的验证 2.生成html代码 Form使用:对用户请求进行验证 前端代码: <form action="/f1.html" ...
- npm install --save
1. npm install:本地安装 2. npm install -g:全局安装 我们在使用 npm install 安装模块或插件时,有两种命令把它们写入到 package.json 文件中去, ...
- JAVA多线程之线程的挂起与恢复(suspend方法与resume方法)
一,介绍 本文讨论JAVA多线程中,使用 thread.suspend()方法暂停线程,使用 thread.resume()恢复暂停的线程 的特点. 先介绍二个关于线程的基本知识: ①线程的执行体是r ...
- Gnucash数据库结构
- Myeclipse/STS 首次在本地部署配置一个Spring MVC 项目 (十二)
1. 在本地新创建一个文件夹 ,做为项目工作空间; 2. 用 Myeclipse 或 STS 进入该文件夹,该文件夹就成为项目的工作空间: 3. 就要进 窗口-首选项,配置: 环境默认编码: 1> ...
- J2EE架构
从整体上讲,J2EE是使用Java技术开发企业级应用的一种事实上的工业标准(Sun公司出于其自身利益的考虑,至今没有将Java及其相关技术纳入标准化组织的体系),它是Java技术不断适应和促进企业级应 ...