Android事件分发机制详解
2019独角兽企业重金招聘Python工程师标准>>>
之前在学习Android事件方法机制的时候,看过不少文章,但是大部分都讲的不是很清楚,我自己理解的也是云里雾里,也尝试过阅读源码,看得我更是不知所措。最近阅读了《Android开发艺术探索》一书中相关的章节,茅塞顿开,写下本文作为阅读笔记,以便以后查阅。
三个重要方法
public boolean dispatchTouchEvent(MotionEvent ev)
事件传递过来的时候这个方法第一个被调用,返回结果受 当前View的ontouchEvent()方法 或者 下一级View的dispatchTouchEvent()方法 返回值影响。
public boolean onInterceptTouchEvent(MotionEvent ev)
这个方法是在 dispatchTouchEvent()方法 内部掉用的,返回值用来判断是否拦截当前事件。
public boolean onTouchEvent(MotionEvent ev)
也是在 dispatchTouchEvent()方法 中掉用,用来处理某一事件。
事件传递规则
书中用了一段伪代码来表示:
也就是说当一个事件到来的时候,当前View的dispatchTouchEvent方法 会被调用,在内部首先调用 onInterceptTouchEvent 判断是否拦截,如果拦截,将事件传递给自己的 onTouchEvent 对事件进行处理。如果不拦截,就将事件传递给子View,调用 子View的dispatchTouchEvent方法,一直到事件被消费。
源码分析
上面的内容讲的很抽象,不好理解,接下来配合源码来讲解,这样更加的容易深入理解事件分发机制。
判断是否拦截
事件到来的时候,View的第一个工作自然是判断是否拦截,下面给出 dispatchTouchEvent 中拦截的相关代码:
这里要注意的是,事件分发机制针对的其实可以看作是一系列的事件,也就是一个事件序列,也就是说一个事件序列由 一个DOWN开头,中间n个MOVE,然后以UP或者CANCEL结束。
代码中 mFirstTouchTarget 在子元素成功处理事件的时候会进行赋值,也就是说 当事件不是DOWN,而且没有子元素成功处理的时候,直接拦截事件自己处理。这很好理解,如果不是DOWN说明事件序列已经开始传递了,那么如果子元素不处理 最开始的DOWN 说明它不想要这个序列,那么就自己处理,一直到新的事件序列到来(也就是 新的DOWN)。也就是说一旦我们处理一个事件就不会多次调用onInterceptTouchEvent方法。
另一种情况是 DOWN到来,也就是新的事件序列开始,或者 子View 成功处理过这个序列,就会进行判断。判断第一步是判断 FLAG_DISALLOW_INTERCEPT 标志位,这个标志位是通过 requestDisallowInterceptTouchEvent 方法设置的,一般是 子View 调用的,如果不允许拦截,就不拦截。如果允许,那就调用自己的 onInterceptTouchEvent 方法来判断。
值得注意的是当 DOWN事件到来 的时候,会重置标志位,且 清除mFirstTouchTarget,就是新序列到来的时候一切重置。
不拦截事件
如果最后不拦截事件,那么就应该分发下去:
就是 遍历子View,通过是否在播放动画和事件是否落在它的范围内来获得合适的 View,如果存在就调用它的 dispatchTouchEvent 方法。
我们需要获得 dispatchTouchEvent 返回的值来判断 子View 是否成功消耗了事件,如果返回的是 true 代表成功消费,那么就会对 mFirstTouchTarget 进行赋值。
newTouchTarget = addTouchTarget(child, idBitsToAssign); alreadyDispatchedToNewTouchTarget = true; break;
这个赋值很重要,如果不消耗那么就不会赋值,也就是说 mFirstTouchTarget== null,那么接下来的事件(同一序列,也就不会再产生DOWN了)都由本 View 消耗,不再分发。
当然,如果最后发现 没有合适的子View 或者 子View返回了false,那么都由 本View 处理,也就是 onTouchEvent,这也就是 为什么事件到了最底层还没被消耗(返回true)就会重新向上传递到上一层的onTouchEvent处理的原因了。
拦截事件
那就开始自己处理事件,接下来的内容就不详细讲解了。
View对事件的处理:
这里的 View不包含ViewGroup,可以看到当要处理事件的时候首先判断是否设置了 OnTouchListener,如果设置了就调用 onTouch方法。如果 onTouch返回了 true,那么就直接返回,不会去调用ontouchEvent。如果返回了false,就回调用 ontouchEvent,返回 onTouchEvent的返回值。
在 onTouchEvent 内部,如果设置了 OnClickListener 就会调用 onClick方法。
总的来说,就是 onTouchListener 级别高于 onTouchEvent,onClickListener 最低。
案例分析
针对上述的理论分析,我们通过以下的Demo来结合实践加深理解。
首先自定义一个 MyViewGroup 和 MyView,代码如下:
MyView:
MyViewGroup:
这里我们 拦截了DOWN事件,接下来点击 MyView 的区域然后 滑动,最后 抬起。
打印结果如下:
明明滑动了一段距离,理论上有很多个MOVE事件,为什么只有三个打印呢?其实之前就已经说明了,我们 拦截了DOWN事件,那么子元素是收不到 DOWN事件 的,结果就是该序列接下来的事件都是我们自己消费,且不会再次掉用 onInterceptTouchEvent,由自己的 onTouchEvent 处理。因为我们的 onTouchEvent 返回了 false,直接导致我们的 dispatchTouchEvent 也返回了 false。那么 MyViewGroup 的上一层就不会把接下来的事件传递给我们了(上一层的 mFirstTouchTarget 没有赋值),所以接下来的事件都不会到来。
我们再改变一下,让 MyViewGroup的onTouchEvent方法返回 true,进行相同的操作,打印结果如下:
省略的打印信息就是 第二条和第三条的多次重复,也就是说在接下来的 MOVE到来的时候,由于之前拦截了 DOWN,所以事件自己处理,不会再掉用 onIntereptTouchEvent。
注意事项
一般在处理滑动冲突的时候重写相关方法,对于DOWN事件是不会拦截的,也就是返回 false,在接下来的 MOVE序列 中判断是否需要拦截。因为如果拦截了DOWN,那么接下来的事件都不会传给子View了,之前已经分析过了。
一般也不会拦截 UP事件,因为UP一般为序列的最后一个事件,拦截不拦截对自己没有什么用处,但是子View就可能因为收不到UP而无法触发click事件。
转载于:https://my.oschina.net/JiangTun/blog/910914
Android事件分发机制详解相关推荐
- Android 系统(199)---Android事件分发机制详解
Android事件分发机制详解 前言 Android事件分发机制是Android开发者必须了解的基础 网上有大量关于Android事件分发机制的文章,但存在一些问题:内容不全.思路不清晰.无源码分析. ...
- View的事件体系之三 android事件分发机制详解(下)
接着上一篇来分析事件分发机制,在看了各位大牛的关于事件分发机制的分析后茅塞顿开,之前看过好几遍郭霖,弘扬以及玉刚大神关于事件体系的讲解,一直看不懂,比较模糊,最近复习时,看到一篇博文,写的相当精彩,看 ...
- Android事件分发机制详解及解决文案:史上最全面、最易懂
点击屏幕Android事件是如何传递,先上图然后再源码解读 源码解读 当用户触摸屏幕首先由当前Activity来分发 public class TouchEventActivity extends A ...
- 安卓自定义View进阶-事件分发机制详解
原文地址:http://www.gcssloop.com/customview/dispatch-touchevent-source Android 事件分发机制详解,在上一篇文章 事件分发机制原理 ...
- Android事件分发溯源详解
前言 前两天华仔给我出了一道难题,我们俩研究了小半天,借着这个契机正好回顾了一下Android事件分发的相关知识点,于是有了这篇文章. Android事件分发机制大家都非常熟悉,大部分文章对这个过程的 ...
- Android View 事件分发机制详解
想必很多android开发者都遇到过手势冲突的情况,我们一般都是通过内部拦截和外部拦截法解决此类问题.要想搞明白原理就必须了解View的分发机制.在此之前我们先来了解一下以下三个非常重要的方法: di ...
- Android事件传递机制详解
总结 dispatchTouchEvent方法:分发点击事件 onInterceptTouchEvent方法:拦截事件(只存在于ViewGroup,View没有此方法), 在dispatchTouch ...
- Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
<div id="container"> <div id="header"> <div class=&qu ...
- Android 事件分发机制分析及源码详解
Android 事件分发机制分析及源码详解 文章目录 Android 事件分发机制分析及源码详解 事件的定义 事件分发序列模型 分发序列 分发模型 事件分发对象及相关方法 源码分析 事件分发总结 一般 ...
最新文章
- Open3d学习计划—高级篇 6(体素化)
- javascript promise编程
- 成为顶尖机器学习算法专家需要知道哪些算法?
- flutter 按钮_flutter好用的轮子推荐二-点赞按钮动画
- 90.前端 :执行方法前提示功能
- iOS - Flutter混合开发
- java格式_java时间格式转换大全
- 查看 SAP Spartacus 基于 Angular 的版本号
- node.js 实现udp传输_Node.js实战15:通过udp传输文件。
- 高考进行时,AI 监考老师已就位!
- RocketMQ安装使用
- Swagger2-注解说明
- exif viewer java,1earn/XSS挑战-WalkThrough.md at master · dizhaung/1earn · GitHub
- 如何使用 Numbers 筛选出特定种类的资料?
- java--分布式ID生成器
- Excel的规划求解【详细步骤】
- 2019年面临的网络安全威胁有哪些
- 外卖返利微信小程序源码
- 【沃顿商学院学习笔记】商业基础——Financing:05 名义利率和实际利率 APR EAR
- 求知以解惑 温故而知新 ——重读哥德尔之一(开篇)