android 点击事件消费,Android View事件分发和消费源码简单理解
Android View事件分发和消费源码简单理解
前言:
开发过程中觉得View事件这块是特别烧脑的,看了好久,才自认为看明白。中间上网查了下singwhatiwanna粉丝的读书笔记,有种茅塞顿开的感觉。
很重要的学习方法:化繁为简,只抓重点。
源码一坨,不要指望每一行代码都看懂。首先是没必要,其次大量非关键代码会让你模糊真正重要的部分。
以下也只是学姐的学习成果,各位同学要想理解深刻,还需要自己亲自去看源码。
2.源码分析
由于源码实在太长,而且也不容易看懂,学姐这里就不贴出来了,因为没必要。
以下是学姐简化版源码。
(1)ViewGroup.dispatchTouchEvent(event)
boolean dispatchTouchEvent(MotionEvent event) {
int action = event.getAction();
//判断ViewGroup是否拦截touch事件。当为ACTION_DOWN或者找到能够接收touch事件的子View
时,由onInterceptTouchEvent(event)决定是否拦截。其他情况,即ACTION_MOVE/ACTION_UP且
没找到能够接收touch事件的子View时,直接拦截。
boolean intercepted;
if (action == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
intercepted = onInterceptTouchEvent(event);
} else {
intercepted = true;
}
//如果ViewGroup不拦截touch事件。在ACTION_DOWN时遍历所有子View,查找能够接收touch事件的
子View。如果找到则设置mFirstTouchTarget,并跳出循环。
boolean alreadyDispatchedToNewTouchTarget = false;
if (!intercepted) {
if (action == MotionEvent.ACTION_DOWN) {
for (int i = childrenCount - 1; i >= 0; i--) {
if (!canViewReceivePointerEvents(child) ||
!isTransformedTouchPointInView(x, y, child, null)) {
continue;
}
if (dispatchTransformedTouchEvent(event, child)) {
//找到mFirstTouchTarget
newTouchTarget = addTouchTarget(child);
alreadyDispatchedToNewTouchTarget = true;
break;
}
}
}
}
//事件下发及消费。如果没找到能够接收touch事件的子View,则由ViewGroup自己处理及消费。
如果找到能够接收touch事件的子View,则由子View递归处理touch事件及消费。
boolean handled = false;
if (mFirstTouchTarget == null) {
handled = dispatchTransformedTouchEvent(event, null);
} else {
if (alreadyDispatchedToNewTouchTarget) {
handled = true;
} else {
while (touchTarget) {
handled = dispatchTransformedTouchEvent(event, child);
}
}
}
return handled;
}
//ViewGroup事件下发。如果无接收touch事件的子View,则由ViewGroup的父类(即View)下发touch事件
如果child非空,则交由子View下发touch事件,子View可以是ViewGroup或View。
boolean dispatchTransformedTouchEvent(MotionEvent event, View child) {
boolean handled;
if (child == null) {
handled = super.dispatchTouchEvent(event);
} else {
handled = child.dispatchTouchEvent(event);
}
return handled;
}
(2)View.dispatchTouchEvent(event)
//View的Touch事件分发。当外部设置了mOnTouchListener时,先交由mOnTouchListener.onTouch(event)消费。
若未消费,则交给View的onTouchEvent(event)消费。onTouchEvent的实现是,如果设置了mOnClickListener,
则执行mOnClickListener.onClick()点击事件。返回值为true,表示消费,否则未消费。
boolean dispatchTouchEvent(MotionEvent event) {
boolean result = false;
if (mOnTouchListener != null && mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
return result;
}
boolean onTouchEvent(MotionEvent event) {
performClick();
}
3.总结
总结下ViewGroup的事件分发及消费过程:
整个过程包括3个部分:判断是否拦截 -> 查找接收touch事件的子View -> 事件下发及消费
判断是否拦截:
(1) ACTION_DOWN 或者 非ACTION_DOWN且找到接收touch事件的子View时,由onInterceptTouchEvent(event)决定是否拦截
(2) 非ACTION_DOWN,且未找到接收touch事件的子View时,标明需要拦截touch事件
这里解释下,影响ViewGroup是否能拦截touch事件有2个因素:是否 找到了接收touch事件的子View 和 onInterceptTouchEvent(event). 而查找接收touch事件的子View这一过程只需要在ACTION_DOWN的时候确定好就行。如果ACTION_DOWN的时候没找到,那么ACTION_MOVE和ACTION_UP肯定也找不到,因此touch事件直接被ViewGroup拦截。如果找到了接收touch事件的子View,那么ACTION_MOVE和ACTION_UP情况下还是要检查下ViewGroup的onInterceptTouchEvent(event),看下是否拦截。
查找接收touch事件的子View:
(1) 两种情况下查找:ACTION_DOWN且ViewGroup不拦截的情况下。
(2) 查找方法:遍历所有子View,如果touch事件的xy坐标在该ViewGroup的某个子View范围内,则针对该子View执行递归分发touch事件操作,如果找到有子View处理touch事件(return true),则跳出循环。
这里解释下查找条件。查找接收touch事件的子View,显然只需要ACTION_DOWN情况下即可,没必要ACTION_MOVE和ACTION_UP都检查,否则重复操作。如果ViewGroup都已经拦截了,显然不需要再去考虑子View怎么样了。
事件下发及消费:
(1)两种情况:ViewGroup下发及消费 或者 ViewGroup的子View下发及消费
(2)如果经过以上两步,没找到接收Touch事件的子View,那么由ViewGroup进行下发及消费,下发及调用流程是:ViewGroup.dispatchTouchEvent -> View.dispatchTouchEvent -> mOnTouchListener.onTouch -> onTouchEvent -> onClick
(3)如果找到接收touch事件的子View,则针对该子View执行touch事件递归下发及消费的操作
补充:
(1) 源码中,mFirstTouchEvent表示接收touch事件的子View
(2) 步骤2和3,都有执行dispatchTransformedTouchEvent(event, child)的操作,步骤2中只是为了查找接收touch事件的子View,步骤3主要目的是进行事件分发及消费。如果步骤2中针对某个子View已经执行了该方法,则步骤3中不再重复执行。个人理解,不知道是否有误。
4.结论
(1) 回调方法
ViewGroup:dispatchTouchEvent -> onInterceptTouchEvent -> onTouchEvent
View: dispatchTouchEvent -> onTouch
(2) 调用顺序
Action执行顺序:ACTION_DOWN -> ACTION_MOVE -> ACTION_UP
ViewGroup: dispatchTouchEvent -> onInterceptTouchEvent -> onTouchEvent()
View: dispatchTouchEvent -> onTouchEvent
事件分发传递顺序: Parent View -> Child View
ViewGroup1.dispatchTouchEvent -> ViewGroup2.dispatchTouchEvent
-> View3.dispatchTouchEvent
(紧跟着是View3.onTouchEvent)
事件消费传递顺序:Child View -> Parent View
View3.onTouchEvent -> ViewGroup2.onTouchEvent
-> ViewGroup1.onTouchEvent
个人理解这种传递顺序,是由dispatchTransformedTouchEvent引起的,这里就是递归调用,整个事件的入口就是ViewGroup.dispatchTouchEvent.
以上就是Android View事件分发和消费源码的文章分享,关于Android view事件的分发机制大家可以在本站搜索相应的文章进行扩展学习!
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
android 点击事件消费,Android View事件分发和消费源码简单理解相关推荐
- 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 二 )
Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...
- 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 )
Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...
- View事件分发机制(源码分析篇)
01.Android中事件分发顺序 1.1 事件分发的对象是谁 事件分发的对象是事件.注意,事件分发是向下传递的,也就是父到子的顺序. 当用户触摸屏幕时(View或ViewGroup派生的控件),将产 ...
- android WebView详解,常见漏洞详解和安全源码(上)
这篇博客主要来介绍 WebView 的相关使用方法,常见的几个漏洞,开发中可能遇到的坑和最后解决相应漏洞的源码,以及针对该源码的解析. 由于博客内容长度,这次将分为上下两篇,上篇详解 WebView ...
- Android自定义底部弹出窗-dialog(2种实现分析+源码)
Android自定义底部弹出窗-dialog(2种实现分析+源码) 上线项目功能抽取,在项目开发中,我们会在许多地方会用到底部自定义弹窗,比如设置:个人账户退出,切换,照片的拍照或者相册的调出,或者一 ...
- 基于Android公交查询系统的设计与实现(论文+程序设计源码+数据库文件)
[摘 要]随着互联网的技术的不断更新发展,人们生活节奏也在不断的加快,对于网络的依赖也越来越紧密,尤其是在等公交,经常会错过班次,但又不知道,下次班次几点发车,这样会导致乘客花掉大把时间在等待,如果可 ...
- Android毕业设计——基于Android+Eclipse的手机安全卫士设计与实现(毕业论文+程序源码)——手机安全卫士
基于Android+Eclipse的手机安全卫士设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于Android+Eclipse的手机安全卫士设计与实现,文章末尾附有本毕业设计的论文和源码下 ...
- Android开发之RecyclerView动态添加item长按删除item源码
我们先看下效果图: 效果还是很不错的. 实现思路: 设置recyclerview为GridLayoutManager布局,单行个数为4个 GridLayoutManager linearLayoutM ...
- Android动态换肤实现原理解析,原理+实战+视频+源码
前言 本人今年25岁,毕业之后进入一家小型的互联网公司工作,在这原公司呆了3年,直至今年才有了跳槽的想法. 每个程序员 都拥有大厂梦,我也不例外,在小公司待久了,感觉人会荒废掉,太轻松,没有压迫感.因 ...
最新文章
- python ftp文件传输服务端
- lisp封装成vla函数_Lisp List 和函数式编程 (in Python)
- python装饰器实例-Python 装饰器简单示例
- 笔记-常见考点-常见问题原因分析
- C - Rencontre Gym - 102798C
- 我们究竟还要学习哪些Android知识?附赠课程+题库
- jenkins+k8s实现持续集成
- xml 连表查询(2) --自关联! 查询父类name,显示父类下的所有子类
- 从程序员到项目经理(三)
- 复杂的指针获取字符串里的内容放入数组
- 算法学习之路|互评成绩计算
- BUUCTF[SCTF2019]Who is he题解
- 修改NPM的默认安装路径
- clientX、pageX、screenX以及offsetX区别
- linux系统文件信息系统满,在Deepin系统中提示系统盘已经满了(/home文件大)的解决方案...
- linux 设备树 otg,linux下充电IC OTG设备供电控制
- SpringCloud Getway
- 2021-05-1java基础
- beego orm 时间相差八小时
- tor浏览器官网地址
热门文章
- 机器学习与高维信息检索 - Note 7 - 核主成分分析(Kernel Principal Component Analysis,K-PCA)
- 强化学习(八) - 深度Q学习(Deep Q-learning, DQL,DQN)原理及相关实例
- Udacity机器人软件工程师课程笔记(三十) - 语义分割与实例实现 - 使用keras实现语义分割
- 【统计图】Echarts实现多条折线图渐变堆叠效果
- Linux上chown命令的高级用法
- Blender2.9全流程创建逼真未来科幻蝙蝠汽车视频教程
- 【blender教程】从头到尾全流程创建一辆吉普车
- 递归/回溯:subsets求子集
- WPF布局(2) 使用的DockPanel面板进行简单的布局
- linux ngxtop安装安装及使用