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

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. 计蒜客NOIP模拟赛(2) D2T3 银河战舰

    [问题描述]    瑞奥和玛德利德是非常好的朋友.瑞奥平时的爱好是吹牛,玛德利德的爱好是戳穿瑞奥吹的牛.    这天瑞奥和玛德利德来到了宇宙空间站,瑞奥向玛德利德炫耀这个空间站里所有的银河战舰都是自己 ...

  2. bzoj 1085: [SCOI2005]骑士精神

    Description 在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士,且有一个空位.在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵 ...

  3. hdu 3954 线段树 (标记)

    Level up Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  4. Linux学习之CentOS(十八)-----恢复Ext3下被删除的文件与 使用grep恢复被删文件内容(转)

    前言 下面是这个教程将教你如何在Ext3的文件系统中恢复被rm掉的文件. 删除文件 假设我们有一个文件名叫 'test.txt' $ls -il test.txt 15 -rw-rw-r– 2 roo ...

  5. JAVAEE——BOS物流项目10:权限概述、常见的权限控制方式、apache shiro框架简介、基于shiro框架进行认证操作

    1 学习计划 1.演示权限demo 2.权限概述 n 认证 n 授权 3.常见的权限控制方式 n url拦截权限控制 n 方法注解权限控制 4.创建权限数据模型 n 权限表 n 角色表 n 用户表 n ...

  6. TCP/IP学习笔记__mbuf

    Socket发送和接收数据都是写入和读取mbuf(存储器缓存)来完成的.下面着重介绍下Sendto函数与mbuf的关系: 以UDP协议为例: 1.UDP的输出执行过程: UDP的输出执行过程 2.协议 ...

  7. axios的兼容性处理

    一.简介 看看官网的简介: "Promise based HTTP client for the browser and node.js" 译:基于 Promise 的 HTTP ...

  8. Luogu P1257 平面上的最接近点对_暴力

    这道题数据不大 两点距离用勾股定理求 #include<iostream> #include<cmath> using namespace std; struct node{ ...

  9. 深入理解Oracle中的随机函数

    --Oracle中取随机值的函数 .dbms_random包 dbms_random包提供了一系列的随机值获取函数以及相关存储过程.下面详细讲解常用的函数和过程. ()dbms_random.rand ...

  10. Node.js 定时器

    稳定性: 5 - 锁定 所有的定时器函数都是全局的.不需要通过 require() 就可以访问. setTimeout(callback, delay[, arg][, ...]) delay 毫秒之 ...