请尊重分享成果,转载请注明出处:

http://blog.csdn.net/hejjunlin/article/details/52298780

上篇分析了View的事件分发流程,留了一个问题:如果上面的EventButton继承TextView的话,按下抬起,会有一个现象,我可以告诉大家现象:就是只有dispatchTouchEvent ACTION_DOWN,onTouch ACTION_DOWN,onTouchEvent ACTION_DOWN这三个,你移动,或者抬起,是没有MOVE,或者UP的。现在说下答案:当时我们在MainActivity中用到了 EventButton.setOnTouchListener(OnTouchListener l)事件监听,返回的是false,表示啥意思,ACTION_DOWN一次支持到switch中去,直接return了false,告诉父view,我处理不了,你不要派任务(事件传递)给我了,所以它只接到了ACTION_DOWN事件,接不到其他的MOVE或者UP,那问题来了,为啥继承Button可以呢?看Button源码,发现啥也没干,就继承了TextView,但用了自己的 com.android.internal.R.attr.buttonStyle,进去一看,发现两个点,一是focusable是true的,二是android:clickable也是true的,这可是问题的答案呢,可查看Android View框架总结(二)View焦点,如何是isfocusable的话,就能先于父view获取到事件。所以它是有MOVE和UP的。有兴趣的,可以把MainActivity中EventButton.setOnTouchListener(OnTouchListener l)事件监听返回true,这个EventButton就能有MOVE和UP了,可以自己动手试试,你看到的才是答案。

<style name="Widget.Button">
    <item name="android:background">@android:drawable/btn_default</item>
    <item name="android:focusable">true</item>
    <item name="android:clickable">true</item>
    <item name="android:textSize">20sp</item>
    <item name="android:textStyle">normal</item>
    <item name="android:textColor">@android:color/button_text</item>
    <item name="android:gravity">center_vertical|center_horizontal</item>
</style> 

前面是上篇遗留的问题,本篇开始分析ViewGroup事件分发(PS:本篇文章中源码均是android 6.0,请知晓)

  • dispatchTouchEvent
  • onInterceptTouchEvent
  • onTouchEvent
  • ViewGroup 事件的分发机制流程图
  • 案例
  • 案例流程图

dispatchTouchEvent

ViewGroup.java -> dispatchTouchEvent()









onInterceptTouchEvent

ViewGroup.java -> onInterceptTouchEvent()

虽然以上代码都有注释,但是还有几个地方说明下:

  • if (!canViewReceivePointerEvents(child)

    这里表示判断当前的down、POINTER_DOWN、HOVER_MOVE三个事件的坐标点是否落在了子控件上,如果落在子控件上,if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign))通过dispatchTransformedTouchEvent传递事件,交由子控件判断是否传递或自己消费处理。如果dispatchTransformedTouchEvent返回true,表示子控件已消费处理,并添加此子控件View到触摸链表,并放置链表头,并结束遍历子控件。newTouchTarget = addTouchTarget(child, idBitsToAssign);false表示未处理。

  • onInterceptTouchEvent表示是否拦截当前事件,返回true表示拦截,如果拦截了事件,那么将不会分发给子View。如:ViewGroup拦截了这个事件,那么所有事件都由该ViewGroup处理,它内部的子View将不会获得事件的传递。ViewGroup是默认不拦截事件的,注意:View是没有这个方法的,也即是说,继承自View的一个子View不能重写该方法,也无需拦截事件,因为它下面没有View了,它要么处理事件要么不处理事件,所以最底层的子View不能拦截事件。

  • 子View消耗了ACTION_DOWN事件,DOWN,MOVE,UP都是一个回合的事件,

    DOWN -> onInterceptTouchEvent -> true 就不向下传事件,且onInterceptTouchEvent不再调用

    DOWN -> onInterceptTouchEvent -> false 传下去

    MOVE -> onInterceptTouchEvent -> true 不传

    每个回合都要经历ViewGroup中的onInterceptTouchEvent的判断是否要拦截接下来的这个子View的事件(当然注意前提条件是每次都是返回false不拦截时,打个不恰当的比喻:这个就好像你买六合彩一样,要是你中了大奖,你至少一段时间内,你都不会再买了,如果没中,那就每次都要买);或者,如果第一次DOWN事件后,由ViewGroup本身消费掉了,那mFirstTouchTarget就为null,为空的话,说明ViewGroup不想这个事件传到它的子view中去,此后MOVE或者UP事件都将在ViewGroup这层自己处理,不会传到子view中去。

  • 打个比喻(对照事件传递机制来),国家(中央)发了一份电报到省里面(相当于一次事件DOWN,MOVE,UP其一都和),关于贫困补助某地区的,如果钱比较多,省里面觉得这油水得捞一捞(拦截onInterceptTouchEvent 返回true),于是把这个事件拦截下,自己消费掉了,直接return true,告诉上面,这个事件消耗完毕,反正上面也不知道(暂且这么说吧),下一次,国家(中央)又发了一份电报到省里面,,关于贫困补助某地区的,这次钱比较少,省里面觉得没啥捞的(不拦截 拦截onInterceptTouchEvent 返回false),就把这个消息原封不动发向了地方政府,地方政府消费这个事件,然后返回true。

dispatchTransformedTouchEvent

ViewGroup.java -> dispatchTransformedTouchEvent()



当传递进来的子View不为null时,就会调用子View的dispatchTouchEvent(event)方法进行事件分发,事件交给子View处理,也即是说,子Viwe符合父view不拦截条件时,事件就会在这里传递给了子View来处理,完成了ViewGroup到子View的事件传递,上面多次调用child.dispatchTouchEvent,这其实就回到上一篇文章中view.dispatchTouchEvent中,而昨天已经分析,view.dispatchTouchEvent接下来会调用view.onTouchEvent返回处理结果,当view事件处理完毕,就会返回一个handled给ViewGroup,就是告诉ViewGroup,是否它消费了这个事件,假如子View的onTouchEvent()返回true,那么就是消耗了事件。

ViewGroup.java -> addTouchTarget()

要是觉得细节太琐碎,总结成下面一张图,看清上面的过程:

案例:

MainActivity

自定义的RelativeLayout



自定义button

布局文件

运行studio,点击按钮,输出log结果:

从log中可以看出:执行过程是从CustomRelativeLayout的dispatchTouchEvent ->CustomRelativeLayout的onInterceptTouchEvent -> EventButton的dispatchTouchEvent ->EventButton的onTouchEvent

在View上触发事件,最先捕获到事件的为View所在的ViewGroup,然后才会到View自身~

同样这个案例,总结成下面一张图,看清上面的过程:

总结

1、一个事件传递从ACTION_DOWN开始,中间有若一个或者多个ACTION_MOVE,最后以ACTION_UP结束。

2、ViewGroup默认不拦截任何事件,所以事件能正常分发到子View处(如果子View符合条件的话),如果没有合适的子View或者子View不消耗ACTION_DOWN事件,那么接着事件会交由ViewGroup处理,并且同一事件序列之后的事件不会再分发给子View了。如果ViewGroup的onTouchEvent也返回false,即ViewGroup也不消耗事件的话,那么最后事件会交由Activity处理。即:逐层分发事件下去,如果都没有处理事件的View,那么事件会逐层向上返回。

3、如果某一个View拦截了事件,那么同一个事件序列的其他所有事件都会交由这个View处理,此时不再调用View(ViewGroup)的onIntercept()方法去询问是否要拦截了。

4、子View可以通过调用getParent().requestDisallowInterceptTouchEvent(true); 阻止ViewGroup对其MOVE或者UP事件进行拦截

5、ViewGroup自身并没有onTouchEvent方法,在dispatchTouchEvent时,会调用dispatchTransformedTouchEvent分发到子view中去,触发ouTouchEvent,但是我们自定义View,继承ViewGroup时,是可以重写ViewGroup的onTouchEvent方法,这是为什么呢?因为ViewGroup继承View,而View是有onTouchEvent方法,所以自定义View继承ViewGroup时,就间接用到了父类的父类中的方法。这样的方处是,对于ViewGroup来说,只是负责事件分发,如果有人继承它,说明想自己控制一些事件发分流程,那么自然相关方法也都可以重写。

第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。

如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易

Android View框架总结(八)ViewGroup事件分发机制的更多相关文章

  1. ViewGroup事件分发机制解析

    最近在看View的事件分发机制,感觉比复杂的地方就是ViewGrop的dispatchTouchEvent函数,便对照着源码研究了一下.故名思意这个函数起到的作用就是分发事件,在具体分析之前还要说明几 ...

  2. android ViewGroup事件分发机制

    1:事件分销过程 自定义一个LinearLayout,重写dispatchTouchEvent onInterceptTouchEvent onTouchEvent,定义一个按键重写dispathcT ...

  3. 【Android开发坑系列】之事件分发机制

    总结一下: 事件序列的定义:从手触摸屏幕(含)到离开屏幕(含)期间所发生的一系列交互事件.主要由ACTION_DOWN.ACTION_MOVE.ACTOIN_UP.ACTION_CANCEL等组成,其 ...

  4. Android:30分钟弄明白Touch事件分发机制

    Touch事件分发中只有两个主角:ViewGroup和View.Activity的Touch事件事实上是调用它内部的ViewGroup的Touch事件,可以直接当成ViewGroup处理. View在 ...

  5. Android View 事件分发机制 源码解析 (上)

    一直想写事件分发机制的文章,不管咋样,也得自己研究下事件分发的源码,写出心得~ 首先我们先写个简单的例子来测试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个My ...

  6. android view事件分发机制

    首先我们先写个简单的例子来测试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个MyButton继承Button,然后把跟事件传播有关的方法进行复写,然后添加上日志 ...

  7. Android View 事件分发机制 源代码解析 (上)

    一直想写事件分发机制的文章,无论咋样,也得自己研究下事件分发的源代码.写出心得~ 首先我们先写个简单的样例来測试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个M ...

  8. Android之事件分发机制

    本文主要包括以下内容 view的事件分发 viewGroup的事件分发 首先来看两张图 在执行touch事件时 首先执行dispatchTouchEvent方法,执行事件分发. 再执行onInterc ...

  9. android菜鸟之路-事件分发机制总结(二)

    ViewGroup事件分发机制 自己定义一个LinearLayout,ImageView和Button,小二,上代码 <LinearLayout xmlns:android="http ...

随机推荐

  1. hdu 5750 Dertouzos 素数

    Dertouzos Time Limit: 7000/3500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total ...

  2. ●BZOJ 1854 [Scoi2010]游戏

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1854 题解: 并查集(还可以用匈牙利算法进行单路增广的二分图匹配) 把每个武器看成是一条边, ...

  3. [BZOJ]1023 cactus仙人掌图(SHOI2008)

    NOIP后的第一次更新嗯. Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus).所谓简单回路就是指在 ...

  4. poj3185 高斯消元

    The Water Bowls Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5329   Accepted: 2081 D ...

  5. Notepad++连接Centos

    Notepad++设置 插件 -- > plugin Manager --> show plugin manager --> NppFtp  安装重启notepad++ 插件 --& ...

  6. springmvc上传文件方法及注意事项

    本文基于注解的配置,敬请留意  基于注解整合 一.springmvc为我们提供两种上传方式配置: org.springframework.web.multipart.commons.CommonsMu ...

  7. 使用C# (.NET Core) 实现状态设计模式 (State Pattern)

    本文的概念性内容来自深入浅出设计模式一书 项目需求 这是一个糖果机的需求图. 它有四种状态, 分别是图中的四个圆圈: No Quarter: 无硬币 Has Quater 有硬币 Gumball So ...

  8. C# 导入excel报错 :不是预期外部表

    错误原因:由于Excel 97-2003的连接格式与Excel 2010 的 不同造成. 解决方案1: 很多人换了2010后,问的最多的问题之一是2003里最经典的ADO中的“provider=Mic ...

  9. Linux之软链接与硬链接

    什么是链接? 链接简单说实际上是一种文件共享的方式,是 POSIX 中的概念,主流文件系统都支持链接文件. 它是用来干什么的? 你可以将链接简单地理解为 Windows 中常见的快捷方式(或是 OS ...

  10. H3C系列之三层交换机系统版本升级

    本文涉及到的硬件与软件交换机:H3C S3600-28TP-SItftp软件:tftpd32小软件升级的文件:S36SI_E-CMW310-R1702P44.zip 关于升级的文件说明如下: S36S ...