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事件分发机制详解相关推荐

  1. Android 系统(199)---Android事件分发机制详解

    Android事件分发机制详解 前言 Android事件分发机制是Android开发者必须了解的基础 网上有大量关于Android事件分发机制的文章,但存在一些问题:内容不全.思路不清晰.无源码分析. ...

  2. View的事件体系之三 android事件分发机制详解(下)

    接着上一篇来分析事件分发机制,在看了各位大牛的关于事件分发机制的分析后茅塞顿开,之前看过好几遍郭霖,弘扬以及玉刚大神关于事件体系的讲解,一直看不懂,比较模糊,最近复习时,看到一篇博文,写的相当精彩,看 ...

  3. Android事件分发机制详解及解决文案:史上最全面、最易懂

    点击屏幕Android事件是如何传递,先上图然后再源码解读 源码解读 当用户触摸屏幕首先由当前Activity来分发 public class TouchEventActivity extends A ...

  4. 安卓自定义View进阶-事件分发机制详解

    原文地址:http://www.gcssloop.com/customview/dispatch-touchevent-source Android 事件分发机制详解,在上一篇文章 事件分发机制原理  ...

  5. Android事件分发溯源详解

    前言 前两天华仔给我出了一道难题,我们俩研究了小半天,借着这个契机正好回顾了一下Android事件分发的相关知识点,于是有了这篇文章. Android事件分发机制大家都非常熟悉,大部分文章对这个过程的 ...

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

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

  7. Android事件传递机制详解

    总结 dispatchTouchEvent方法:分发点击事件 onInterceptTouchEvent方法:拦截事件(只存在于ViewGroup,View没有此方法), 在dispatchTouch ...

  8. Android事件分发机制完全解析,带你从源码的角度彻底理解(上)

    <div id="container">         <div id="header">     <div class=&qu ...

  9. Android 事件分发机制分析及源码详解

    Android 事件分发机制分析及源码详解 文章目录 Android 事件分发机制分析及源码详解 事件的定义 事件分发序列模型 分发序列 分发模型 事件分发对象及相关方法 源码分析 事件分发总结 一般 ...

最新文章

  1. Open3d学习计划—高级篇 6(体素化)
  2. javascript promise编程
  3. 成为顶尖机器学习算法专家需要知道哪些算法?
  4. flutter 按钮_flutter好用的轮子推荐二-点赞按钮动画
  5. 90.前端 :执行方法前提示功能
  6. iOS - Flutter混合开发
  7. java格式_java时间格式转换大全
  8. 查看 SAP Spartacus 基于 Angular 的版本号
  9. node.js 实现udp传输_Node.js实战15:通过udp传输文件。
  10. 高考进行时,AI 监考老师已就位!
  11. RocketMQ安装使用
  12. Swagger2-注解说明
  13. exif viewer java,1earn/XSS挑战-WalkThrough.md at master · dizhaung/1earn · GitHub
  14. 如何使用 Numbers 筛选出特定种类的资料?
  15. java--分布式ID生成器
  16. Excel的规划求解【详细步骤】
  17. 2019年面临的网络安全威胁有哪些
  18. 外卖返利微信小程序源码
  19. 【沃顿商学院学习笔记】商业基础——Financing:05 名义利率和实际利率 APR EAR
  20. 求知以解惑 温故而知新 ——重读哥德尔之一(开篇)

热门文章

  1. 一帖搞定U盘系统制作及安装苹果mac os引导U盘安装windows7
  2. Windows Live Writer新版新功能试用
  3. Asp.net团队疯了(同时发布WebMatrix, Razor, MVC3和Orchard)
  4. 聊聊flink的StateTtlConfig
  5. SD-WAN:MSP连接
  6. Windows Phone 7 网络编程之留言板应用
  7. 怎样用批处理来执行多个exe文件
  8. SNMP AGENT函数介绍
  9. iOS培训教程——设置默认语言
  10. 关于routerOS设置PPPOE与HOTSPOT并存的说明