【Android - 进阶】之事件分发机制
参考资料:
View事件分发:http://blog.csdn.net/pi9nc/article/details/9281829
ViewGroup事件分发:http://blog.csdn.net/guolin_blog/article/details/9153747
1 概述
Android中的布局是按树形结构层级排列的,根布局往往是一个ViewGroup,如LinearLayout,其中包裹一些子View或子ViewGroup,子ViewGroup中又包裹着它的子View或子ViewGroup,依此类推。
每当触摸了屏幕上的一个“东西”,都会触发这个“东西”的dispatchTouchEvent()方法,负责事件的分发。这个方法是从它的父类View或ViewGroup中继承来的。
因此,我们想要了解Android中的事件分发机制,就需要分别了解View的事件分发机制和ViewGroup的事件分发机制。
2 View事件分发
一般地,我们给一个控件添加事件,通常会调用setOnTouchListener()和setOnClickListener()这两个方法,前者是为了监听手指的按下、抬起、滑动等细节操作,而后者只是为了监听点击控件的操作。从上面的概述可以知道,无论是哪种操作,都是通过dispatchTouchEvent()方法来分配的。
在View类的dispatchTouchEvent()方法中,先判断这个View是否注册了OnTouchListener监听器,如果注册了,则回调其中的onTouch()方法;如果没有注册,则调用View类中的onTouchEvent()方法。
OnTouchListener中的onTouch()方法是回调给程序员编写的,这个方法有一个布尔类型的返回值,如果返回true则终止本次事件的分发,否则依然会调用View类中的onTouchEvent()方法。对应的部分源码如下:
if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
在View类的onTouchEvent()方法中判断这个View是否是可点击的(clickable),如果是则判断这个View是否注册了OnClickListener,如果注册了就调用其中的onClick()方法。对应的部分源码如下:
public boolean onTouchEvent(MotionEvent event) {
if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
|| (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
performClick();
return true;
}
return false;
}
public void performClick() {
if (li != null && li.mOnClickListener != null) {
li.mOnClickListener.onClick(this);
}
}
从上面的代码中可以看出,如果一个控件时clickable的,那么onTouchEvent()就一定会返回true,否则返回false。
因此,当我们为一个控件同时设置了setOnTouchListener()和setOnClickListener()这两个方法时,会先回调OnTouchListener中的onTouch()事件,当onTouch()返回true时,才会再回调OnClickListener中的onClick()事件。
这里还需要注意的一点是,给一个控件设置了touch事件后,每次点击它时,都会触发一系列的ACTION_DOWN、ACTION_MOVE和ACTION_UP等事件。在此过程中,如果某一个ACTION返回了false,那么后面的一系列ACTION就不会再执行了。简单的说,当dispatchTouchEvent()在进行事件分发的时候,只有前一个ACTION返回true,才会触发后一个ACTION。
3 ViewGroup事件分发
当一个事件到达一个ViewGroup的时候,会递归的在它的树级结构中查找这个事件的处理者:依次遍历这个ViewGroup中的所有子View和子ViewGroup,调用它们的dispatchTouchEvent()方法,如果判断可以处理这个事件则返回true,否则返回false;当一个ViewGroup中的所有子View和子ViewGroup的dispatchTouchEvent()方法都返回false,则这个ViewGroup的dispatchTouchEvent()也返回false。
ViewGroup中有一个方法叫做onInterceptTouchEvent(),它标识这个ViewGroup是否要拦截其下的View的事件,默认返回的是false,表示不拦截。我们可以通过在自定义ViewGroup中重写这个方法设置其返回值为true,或者通过requestDisallowInterceptTouchEvent()方法获取拦截权限。
当ViewGroup的onInterceptTouchEvent()方法返回true时,所有属于这个ViewGroup中某个View的事件都会被这个ViewGroup拦截,即这个ViewGroup就成为了这个事件的处理者来处理这个事件。
4 综述
每当触摸了一次屏幕,根布局(ViewGroup)就会发出一次递归搜索,在其下层的布局或控件树中寻找拦截这次事件的控件,如果有控件或布局对这次事件进行了拦截,则表示这个控件或布局就是这次事件的处理者。
无论最终获取这个事件处理权的是View还是ViewGroup(以下统称为控件),都调用它的dispatchTouchEvent()方法对事件进行处理。
总之,Android中的事件分发机制的流程图如下图所示:
最后,用文字来描述一下完整的事件分发机制:
1、当我们在手机屏幕上点击了一下,就是在当前界面的Activity上点击了一下,就会触发当前Activity的dispatchTouchEvent()方法;
2、在Activity的dispatchTouchEvent()方法中,通过getWindow()方法找到当前Activity的Window对象(PhoneWindow对象),然后调用Window对象的superDispatchTouchEvent()方法;
3、在Window的superDispatchTouchEvent()方法中,通过getDecorView()方法找到当前Activity中的顶层View(顶层View一般都是ViewGroup),开始View的事件传递;
4、顶层View调用dispatchTouchEvent()方法,开始实际的事件分发,具体流程如下:
(1)判断这个ViewGroup是否拦截事件,即它的onInterceptTouchEvent()方法是否返回true,如果返回true则事件会交给这个ViewGroup处理,即它的onTouchEvent()方法会被调用;
(2)如果这个ViewGroup不拦截事件,则递归调用其下所有View的dispatchTouchEvent()方法,找到事件处理者的View;
(3)先判断目标View是否注册了OnTouchListener,如果注册了,则调用OnTouchListener中的onTouch()方法,验证其返回值;
(4)如果onTouch()方法返回false,表示View还没有将这个事件消费掉,会继续执行View的onTouchEvent()方法;如果onTouch()返回true,则不会继续执行onTouchEvent()方法,直接结束事件传递;
(5)如果这个View重写了onTouchEvent()方法,则会先调用重写的内容;
(6)如果给这个View设置了OnClickListener,则会在onTouchEvent()中的代码执行之后,调用OnClickListener中onClick()方法中的代码;
5、在上面的事件传递过程中,如果有一个View接管了事件,那么事件就不会继续向下传递,将这个View的信息层层上报到顶层View之后,结束事件传递;
6、如果顶层View发现底下的所有View都没有接管这个事件,那么这个事件最终会回传给Activity处理,即Activity的onTouchEvent()方法会被调用。
【Android - 进阶】之事件分发机制的更多相关文章
- Android中的事件分发机制
Android中的事件分发机制 作者:丁明祥 邮箱:2780087178@qq.com 这篇文章这周之内尽量写完 参考资料: Android事件分发机制完全解析,带你从源码的角度彻底理解(上) And ...
- Android view 的事件分发机制
1 事件的传递顺序是 Activity -> Window -> 顶层View touch 事件产生后,最先由 activity 的 dispatchTouchEvent 处理 /** * ...
- Android中的事件分发机制总结
Android 的事件分发机制 一.View的事件分发总结: View的onTouchEvent和OnTouch区别 还是以自定义的TestButton为例. 我们可以通过重写onTouchEven ...
- Android的Touch事件分发机制简单探析
前言 Android中关于触摸事件的分发传递是一个很值得研究的东西.曾不见你引入了一个ListView的滑动功能,ListView就不听你手指的指唤来滚动了:也不知道为啥Button设置了onClic ...
- Android View的事件分发机制
准备了一阵子,一直想写一篇事件分发的文章总结一下.这个知识点实在是太重要了. 一个应用的布局是丰富的,有TextView,ImageView,Button等.这些子View的外层还有ViewGroup ...
- Android View的事件分发机制和滑动冲突解决方案
这篇文章会先讲Android中View的事件分发机制,然后再介绍Android滑动冲突的形成原因并给出解决方案.因水平有限,讲的不会太过深入,只希望各位看了之后对事件分发机制的流程有个大概的概念,并且 ...
- Android程序员事件分发机制学习笔记
通过问题来学习一个东西是很好的方法.学习Android中View的事件体系,我也通过给自己提问题,在解决问题的同时也就知道了其中原理. 首先来几个问题起步: 什么是事件?什么是事件分发机制? 在我们通 ...
- Android View的事件分发机制探索
概述 Android事件传递机制也是Android系统中比较重要的一块,事件类型有很多种,这里主要讨论TouchEvent的事件在framework层的传递处理机制.因为对于App开发人员来说,理解f ...
- 浅谈Android中的事件分发机制
View事件分发机制的本质就是就是MotionEvent事件的分发过程,即MotionEvent产生后是怎样在View之间传递及处理的. 首先介绍一下什么是MotionEvent.所谓MotionEv ...
- Android巩固之事件分发机制
https://www.cnblogs.com/liaojie970/p/5869152.html onTouchEvent是真正用来进行业务逻辑处理的地方,返回true表示已经将该事件消费,返回fa ...
随机推荐
- C++ 数据类型及相关问题 及输出精度控制
1.有哪些数据类型? 2.数据类型在不同的编译器会有不同的位宽,如何得知? 使用如下命令: cout<<sizeof(int)<<endl; cout<<sizeo ...
- PHP漏洞全解(八)-HTTP响应拆分
本文主要介绍针对PHP网站HTTP响应拆分,站在攻击者的角度,为你演示HTTP响应拆分. HTTP请求的格式 1)请求信息:例如“Get /index.php HTTP/1.1”,请求index.ph ...
- 《暗黑世界》安卓APK 编译流程详细说明教程!(图文)
原地址:http://bbs.gameres.com/forum.php?mod=viewthread&tid=223671 关于开发环境的搭建,之前的相关文档已经很详细的说明,对环境的搭建请 ...
- loadrunner_Controller技巧_overlay
在scenario运行期间,我们经常有类似于:总结Vu数变化,Tps 或者response time变化的趋势或者对比response time 和 tps,那么我们就用的到 Controller的图 ...
- 驱动开发 - WDK 调试及 SVN 环境搭建
由于从公司辞职了,所以以前在公司里搭建的驱动开发环境也就 Game Over 了, 同样由于那环境是很久以前搭建的,自己也有很多记不清楚的地方了, 而且其中还是有很多需要注意的地方的,所以在这里顺便做 ...
- 关于方程x^2+y^2=p (p为素数)的解问题
问题描述:对于方程,其中为素数,x,y为整数,且,输出符合条件的x,y. 分析:对于本方程,我们通过费马平方和定理知道,只有奇素数p满足这个条件时才有解. 那么当此方程有解时,解有几个呢?很明显不可能 ...
- PHP数组排列
一.先看最简单的情况.有两个数组: $arr1 = array(1,9,5);$arr2 = array(6,2,4); array_multisort($arr1,$arr2); print_r($ ...
- iOS7 iOS8 毛玻璃效果的分别实现
iOS8用系统的, iOS7用第三方的(效果还是挺快的.) https://github.com/KiranPatel-iOS/KPBlurEffect [_headBGIV sd_setImageW ...
- C# 多线程(lock,Monitor,Mutex,同步事件和等待句柄)
本篇从 Monitor,Mutex,ManualResetEvent,AutoResetEvent,WaitHandler 的类关系图开始,希望通过本篇的介绍能对常见的线程同步方法有一个整体的认识,而 ...
- C# 操作 Word 修改word的高级属性中的自定义属性2
word的类库使用的是word2007版本的类库,类库信息见下面图片,折腾了半天,终于找到入口,网上 很多说的添加或者修改word的高级属性中的自定义属性都是错误的,感觉都是在copy网上的代码,自己 ...