View 事件传递体系知识梳理(1) 事件分发机制
一、事件分发概述
1.1 事件分发的关键方法
对于ViewGroup
来说,与事件分发相关的方法包括:
public boolean dispatchTouchEvent(MotionEvent event)
public boolean onInterceptTouchEvent(MotionEvent event)
public boolean onTouchEvent(MotionEvent event)
复制代码
对于View
来说,与事件分发相关的方法包括:
public boolean dispatchTouchEvent(MotionEvent event)
public boolean onTouchEvent(MotionEvent event)
复制代码
1.2 Down
分发的理解
对于Down
分发的过程,网上看了很多的例子和图,但是都没能好好理解,最后还是自己总结了一种方案,这个方案的核心就是染色:
- 初始的时候
View
树上每个节点都是白色的。 - 从子节点的角度来看,当它被父节点调用
dispatchTouchEvent
时,在返回之前都会有一个返回值,如果这个返回值为真,那么它自己就会变成红色。 - 从父节点的角度来看,当它给子节点调用
dispatchTouchEvent
时,它既是在尝试给子节点进行染色,也是在尝试给自己着色,当某个子节点的dispatchTouchEvent
方法返回时,取该子节点的颜色对自己进行着色;如果遍历完它所有的子节点,它仍然没有变成红色,那么调用它自己的onTouchEvent
,如果返回true
,那么把自己染成红色。 - 对于一个
ViewGroup/View
来说,有可能染色成功只包括两种途径:子节点的dispatchTouchEvent
返回时,取子节点的颜色对自己着色;通过自己的onTouchEvent
方法来着色。并且,只有前一种途径不成功时才会用后一种途径。 - 只要节点变成了红色,那么就不需要再尝试对自己进行染色了,也就是上面那条说的:利用子节点的
dispatchTouchEvent
来染色或者通过自己的onTouch
来染色,它会直接返回。
从伪代码来看:
public Color color = white;public boolean dispatchTouchEvent(MotionEvent event) {int childCount = getChildCount;for (i = childCount - 1; i >= 0; i--) {View child = getChildAt(i);boolean result = child.dispatchTouchEvent(event);if (result) {color = RED;return true;}}boolean touchRes = onTouchEvent(event);if (touchRes) {color = RED;}return touchRes;
}
复制代码
在Down
事件分发完后,我们可以发现这么个现象。
- 假如一个节点是红色的,那么它最多只可能有一个红色的子节点。
- 假如一个节点是红色的,那么必然会有一条唯一的路径,该路径会通过该红色节点连接到根节点。
- 假如一个节点是白色的,那么它所有的后代节点都一定是白色的。
1.3 Down
分发的特点
对于一个没有重写以上关键方法并且位于View
树上的ViewGroup/View
来说,它Down
事件的分发具有以下几个特点:
1.3.1 dispatchTouchEvent
dispatchTouchEvent
是否被回调,由它的父容器决定的。- 假如是它不是叶节点,当它的
dispatchTouchEvent
被调用时,它会先逆序依次调用下一级子节点的dispatchTouchEvent
方法。 - 如果在以上遍历中间有任何一个子节点的
dispatchTouchEvent
返回了true
,那么不会继续调用剩余未遍历子节点的dispatchTouchEvent
,并且它自身的onTouchEvent
不会被回调。
1.3.2 onInterceptTouchEvent
只有ViewGroup
才有,它是否被回调取决于dispatchTouchEvent
是否被回调。
1.3.3onTouchEvent
onTouchEvent
是由自己回调的,是否被回调,必须同时满足以下两个条件:
dispatchTouchEvent
被回调。- 满足以下两种情况之一:
- 它是整个
View
树的叶节点 - 它拥有子节点,但是它所有子节点的
dispatchTouchEvent
都返回false
。
1.4 Move/Up
分发
在Move/Up
事件分发的时候,其实就是根据之前着色的结果来往下传递事件,它的传递只需要遵循下面的原则:只会分发给红色的节点,遇到白色的节点就停止往下分发。
1.5 简单举例
我们举一个简单的例子:
- 前提条件:
ViewGroup1
返回true
。 - 过程:
Root
调用ViewGroup1
的dispatchTouchEvent
,而ViewGroup1
此时是白色,因此它继续调用它的子节点,也就是View21
的dispatchTouchEvent
,但是View21
没有子节点,因此它调用自己的onTouchEvent
,它的dispatchTouchEvent
方法返回,而此时,ViewGroup2
所有的子节点都遍历完了,它依然没有变成红色,因此它调用自己的onTouchEvent
,由于该方法返回false
,因此它也返回了,并且在返回时依然是白色。接下来Root
取ViewGroup2
的颜色对自己着色,着色完成之后发现自己仍然是白色,那么它就继续调用有可能使自己染色成功的方法,ViewGroup1
的dispatchTouchEvent
,由于它的dispatchTouchEvent
返回true
,因此它会把自己染成红色,由于它已经变成红色了,那么它也没有权利对子节点进行染色,因此它的dispatchTouchEvent
返回,Root
收到返回值时,取ViewGroup1
的颜色对自己进行着色,结果它发现自己是红色了,那么Root
也不会调用任何可能对自己染色的方法,而是直接返回了。 - 结果:
ROOT
和ViewGroup1
变为红色节点。
二、示例
只要理解了上面的思想,其实各种情况都可以对应到,下面的例子只是为了让大家能够证明自己的想法是否正确罢了,所以就不过多解释了:
<?xml version="1.0" encoding="utf-8"?>
<com.example.lizejun.repoviews.LogFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:tag="ViewGroup$Root"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.example.lizejun.repoviews.MainActivity"><com.example.lizejun.repoviews.LogFrameLayoutandroid:tag="ViewGroup1"android:layout_width="match_parent"android:layout_height="match_parent"><com.example.lizejun.repoviews.LogTextViewandroid:tag="ViewGroup1$View1"android:layout_width="match_parent"android:layout_height="match_parent" /><com.example.lizejun.repoviews.LogTextViewandroid:tag="ViewGroup1$View2"android:layout_width="match_parent"android:layout_height="match_parent" /></com.example.lizejun.repoviews.LogFrameLayout><com.example.lizejun.repoviews.LogFrameLayoutandroid:tag="ViewGroup2"android:layout_width="match_parent"android:layout_height="match_parent"><com.example.lizejun.repoviews.LogTextViewandroid:tag="ViewGroup2$View"android:layout_width="match_parent"android:layout_height="match_parent"/></com.example.lizejun.repoviews.LogFrameLayout>
</com.example.lizejun.repoviews.LogFrameLayout>
复制代码
2.1 不改变任何函数的返回值
2.2 ViewGroup2
的dispatchTouchEvent
返回false
2.3 ViewGroup2
的dispatchTouchEvent
返回true
2.4 ViewGroup1
下的孩子节点View2
返回了false
2.5 ViewGroup1
下的孩子节点View2
返回了true
2.6 ViewGroup2
的onTouchEvent
返回了false
2.7 ViewGroup2
的onTouchEvent
返回了true
2.8 ViewGroup1
下的孩子节点View2
返回了false
2.9 ViewGroup1
下的孩子节点View2
返回了true
View 事件传递体系知识梳理(1) 事件分发机制相关推荐
- View 绘制体系知识梳理(7) getMeasuredWidth 和 getWidth 的区别
前言 前几天被问到了getMeasuredWidth和getWidth之间的区别,因此回来看了一下源码,又顺便复习了一遍measure/layout/draw的过程,有兴趣的同学可以看前面的几篇文章 ...
- jquery父元素和子元素点击事件传递问题_不可把父元素的事件传递给子元素_事件无限循环传递...
前述:jquery中: 当一个元素的点击事件被触发时,会自动将该事件向父级元素逐级专递. 但是实际场景当中,我们可能会遇到需要在父级元素中定义点击事件,来触发特定子元素的点击事件,我就遇到了这么一个问 ...
- 《软件工程与实践》 |(九)软件工程新技术及体系 知识梳理
系列索引: <软件工程与实践>第三版 软件工程课程知识梳理 目录 系列索引: <软件工程与实践>第三版 软件工程课程知识梳理 本章重难点: 9.1 软件工程新技术 9.1.1 ...
- View 绘制体系知识梳理(4) 绘制过程之 Layout 详解
一.布局的起点 - performTraversals 和前面分析测量过程类似,整个布局的起点也是在ViewRootImpl的performTraversals当中: private void per ...
- 动画体系知识梳理(1) 转场动画 ContentTransition 理论篇
一.概述 在Android 5.0当中,Google基于Android 4.4中的Transition框架引入了转场动画,设计转场动画的目的,在于让Activity之间或者Fragment之间的切换更 ...
- android touch事件坐标原点,图解Android:Touch事件传递机制
前言 Android事件管理机制是一名专业Android研发工程师必须要了解的核心知识之一,深入了解一下该机制无论对我们日常开发还是找工作,乃至于对我们的架构思想都有很大的帮助.Android中我们用 ...
- Android Touch事件传递机制 二:单纯的(伪生命周期) 这个清楚一点
转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在 ...
- Android事件机制:事件传递和消费
Android中的事件在表现形式上有很多,如onTach.onClick和onLongClick等,在具体微观上的表现形势有action_down.action_move和action_up等. ...
- 【Android 事件分发】事件分发源码分析 ( Activity 中各层级的事件传递 | Activity -> PhoneWindow -> DecorView -> ViewGroup )
Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...
最新文章
- 从传统到深度学习:浅谈点云分割中的图结构
- RSPN技术华为交换机(s2000hi)
- Spring boot admin 升级到2.3.1 遇到的问题总结
- 【华为云技术分享】【测试微课堂】 有的放矢制定测试计划
- 转载:如果你到了20岁,还没到 25岁 作者:李开复
- 利用Lua脚本语言制作魔兽WOW插件
- 完全免费软件开发论坛介绍
- 计算机毕业设计java+ssm的在线投票管理系统(源码+系统+mysql数据库+Lw文档)
- 直播软件开发,直播软件源码+三级分销模式的搭建
- 路由器 AP、路由、中继、桥接模式的区别
- 唯物辩证法-矛盾论(普遍性+特殊性+斗争性+同一性)
- 中国电话区号(CSV)
- Ping命令出现 Packet filtered
- uniapp封装request请求简洁明了(使用Promise封装)
- 计算机函数sumif求平均值,用sumif函数如何求平均值
- 基于深度学习的手写数字实现及超简单的英文字母识别
- openwrt配置文件选项 /etc/config/wireless
- Linux鸟哥的私房菜(硬件)
- 全国计算机等级报名12,全国计算机等级考试12月20日开始报名!注意事项请查收!...
- 敏捷转型行动笔记:内部敏捷教练培训资料分享——基础篇(夯实精益敏捷思想,掌握相关实践)
热门文章
- JetBrains IDE 调试快捷键(debug、全)
- Linux系统编程:fifo有名管道的使用
- css选择器中:first-child与:first-of-type的区别
- RPC-非阻塞通信下的同步API实现原理,以Dubbo为例
- python - HTMLTestRunner 测试报告模板设置
- 关于使用jquery修改hover伪标签的样式
- .Net学习笔记----2015-06-28(值类型和引用类型)
- tableView中deselectRowAtIndexPath的作用
- Javascript 链式运动框架——逐行分析代码,让你轻松了解运动的原理
- 如何通过数据分析鉴别假微博大V?