Android GUI之View事件处理(二)
在上篇文章中,我们分析了View的事件处理过程,当然这里的View是指基本的View。当View接收到Touch事件时,首先会调用dispacheTouchEvent方法,在这个方法中会调用OnTouchListener和OnTouchEvent进行具体的事件处理,OnTouchListener优先于OnTouchEvent。如果在OnTouchListener的onTouch方法返回true,则后续的OnTouchEvent不再执行。而在OnTouchEvent根据Touch的动作进行具体的事件处理。这是我们在上篇文章中得到的结论,那么我们还需要考虑一个问题,我们的基本控件都是在布局文件中,而后显示在手机屏幕上,那么当我们触摸屏幕的时候,是如何将事件从Activity传递到布局(ViewGroup)再到View的呢?
首先,我们先看一个简单的例子,我们先自定义一个View和ViewGroup分别去重新他们的dispatchTouchEvent和onTouchEvent方法,具体代码如下:
public class MyButton extends Button {
private static final String TAG="MyButton";
public MyButton(Context context) {
super(context);
}
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
Log.i(TAG,"自定义按钮的dispatchTouchEvent执行了:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG,"自定义按钮的dispatchTouchEvent执行了:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG,"自定义按钮的dispatchTouchEvent执行了:ACTION_UP");
break;
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
Log.i(TAG,"自定义按钮的OnTunchEvent执行了:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG,"自定义按钮的OnTunchEvent执行了:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG,"自定义按钮的OnTunchEvent执行了:ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
}
public class MyGroupView extends LinearLayout {
private static final String TAG="MyGroupView";
public MyGroupView(Context context) {
super(context);
}
public MyGroupView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
Log.i(TAG,"自定义ViewGroup的dispatchTouchEvent执行了:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG,"自定义ViewGroup的dispatchTouchEvent执行了:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG,"自定义ViewGroup的dispatchTouchEvent执行了:ACTION_UP");
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
Log.i(TAG,"自定义ViewGroup的onTouchEvent执行了:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG,"自定义ViewGroup的onTouchEvent执行了:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG,"自定义ViewGroup的onTouchEvent执行了:ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
}
在Activity中同样重写这两个方法,并为按钮绑定点击事件监听器具体如下:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
Log.i(TAG, "Activity的dispatchTouchEvent执行了:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG,"Activity的dispatchTouchEvent执行了:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG,"Activity的dispatchTouchEvent执行了:ACTION_UP");
break;
}
return super.dispatchTouchEvent(ev);
} @Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
Log.i(TAG,"Activity的OnTunchEvent执行了:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG,"Activity的OnTunchEvent执行了:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG,"Activity的OnTunchEvent执行了:ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
运行程序,点击按钮,可以看到Log信息如下,从运行日志中,我们看以看出,事件的传递顺序依次为ActivityàViewGroupàView。

在Activity,我们看到dispatchTouchEvent方法最终调用了super.dispatchTouchEvent方法,追踪代码,可以看到在Activity的源码中,其方法的具体实现为:
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
从源码中,可以看到,在Activity中是否执行onTouchEvent,完全取决于Window对象的superDispatchTounchEvent方法的返回值,之前的文章中提到过,Activity的Window实现类为PhoneWindow,找到此类的源码,查看此方法,内容如下:
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
很明显,调用了DecorView的superDispatchTouchEvent方法,在其具体实现中调用了父类也就是FrameLayout的dispatchTouchEvent方法,而FrameLayout并没有重写此方法,因此我们需要找到ViewGroup中的方法实现,此方法有点长,在这里就不全部贴出来,有兴趣的可以自行查看,在此方法中关键的地方调用了如下两个方法:
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
View child, int desiredPointerIdBits)
public boolean onInterceptTouchEvent(MotionEvent ev)
简单的讲上述两个方法的作用为dispatchTransfromedTouchEvent将事件传递给子View,而方法onInterceptTouchEvent则决定了是否将会拦截事件的分发。至此,View事件的传递过程我们有了基本的认识,这还不够,我们继续分析。
之前有提过,一次完整事件是由Touch的几个动作(ACTION_DOWN、ACTION_MOVE、ACTION_UP)组成的,而且事件的开始总是由ACTION_DOWN开始,ACTION_UP结束。对上面的例子稍作修改,在MyViewGroup重写onInterceptTouchEvent方法。
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.i(TAG,"自定义ViewGroup的onInterceptTouchEvent执行了");
return super.onInterceptTouchEvent(ev);
}
运行后,输出日志如下,可以看到该方法返回false时,(ViewGroup中的默认返回值),并没有影响到事件的传递处理过程。

再次修改该方法,将返回值,修改为true,日志输出结果如下,从结果看以看出事件并没有在传递给MyButton,而是被拦截了,被拦截后,执行了MyViewGroup的onTouchEvent方法。

恢复onInterceptTouchEvent并修改dispatchTouchEvent,将其返回值改为true,运行日志结果如下,很明显事件被取消了,不再向下分发。

恢复MyViewGroup的dispatchTouchEvent方法,修改MyButton,将onTouchEvent的返回值修改为true,运行日志结果为:

将返回值修改为false,日志结果为:

通过日志对比,我们可以发现当返回true时,包含MyButton的View的OnTouchEvent并没有执行,也就是意味该事件被MyButton处理了,即消费掉了。
通过以上分析,我们可以得到如下结论:
1、事件从Activity接收后,经ViewGroup最终传递到View中。该过程中涉及的方法有三个,具体如下:
DispatchTouchEvent
OnTouchEvent
onInterceptTouchEvent
其中onInterceptTouchEvent为ViewGroup中的方法。
2、如果DispatchTouchEvent方法中返回值为true,在事件被取消,不再继续分发。
3、如果View 的OnTouchEvent方法返回值为true,在意味着事件已被处理;如果返回值为false,则会依次向上调用父容器的onTouchEvent进行事件处理。
3、如果onInterceptTouchEvent返回值为true,则事件被拦截,不再向下分发,同时调用自己的OnTouchEvent方法进行事件处理
想要了解更多内容的小伙伴,可以点击查看源码,亲自运行测试、
出处:http://www.cnblogs.com/jerehedu/
版权声明:本文版权归烟台杰瑞教育科技有限公司和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
技术咨询:

Android GUI之View事件处理(二)的更多相关文章
- Android GUI之View事件处理
Android中的事件分为按键事件和触屏事件,本篇文章将分析View是如何处理Touch事件的.在View中定义了许多触屏事件,比如OnClick.OnLongClick等等,这些事件都是由一次To ...
- Android GUI之View测量
在上篇文章(http://www.cnblogs.com/jerehedu/p/4607599.html#gui)中,根据源码探索了View的绘制过程,过程有三个主要步骤,分别为测量.布局.绘制.系统 ...
- Android GUI之View绘制流程
在上篇文章中,我们通过跟踪源码,我们了解了Activity.Window.DecorView以及View之间的关系(查看文章:http://www.cnblogs.com/jerehedu/p/460 ...
- Android GUI之View布局
在清楚了View绘制机制中的第一步测量之后,我们继续来了解分析View绘制的第二个过程,那就是布局定位.继续跟踪分析源码,根据之前的流程分析我们知道View的绘制是从RootViewImpl的perf ...
- android中实现view可以滑动的六种方法续篇(二)
承接上一篇,上一篇中讲解了实现滑动的第五种方法,如果你还没读过,可点击下面链接: http://www.cnblogs.com/fuly550871915/p/4985482.html 这篇文章现在来 ...
- 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)
Android 的窗口管理系统 (View, Canvas, WindowManager) 在图解Android - Zygote 和 System Server 启动分析一 文里,我们已经知道And ...
- Android特效专辑(十二)——仿支付宝咻一咻功能实现波纹扩散特效,精细小巧的View
Android特效专辑(十二)--仿支付宝咻一咻功能实现波纹扩散特效,精细小巧的View 先来看看这个效果 这是我的在Only上添加的效果,说实话,Only现在都还只是半成品,台面都上不了,怪自己技术 ...
- Android自定义View(二)
前言 魅族手机的闹钟应用中有个倒计时,这个控件还是蛮有趣的.左边是魅族闹钟,右边是我们最终实现的效果,虽然有些细节还需优化,不过基本上已经达到了想要的效果,我们先来就来看看如何实现吧. 分析 确定宽高 ...
- Android自定义控件View(二)继承控件
在前一篇博客中学习了Android自定义控件View的流程步骤和注意点,不了解的童鞋可以参考Android自定义控件View(一).这一节开始学习自定义控件View(二)之继承系统已有的控件.我们来自 ...
随机推荐
- JAVAEE——宜立方商城03:商品类目选择、Nginx端口或域名区分虚拟机、Nginx反向代理、负载均衡、keepalived实现高可用
1. 学习计划 第三天: 1.商品类目选择(EasyUI的tree实现) 2.图片上传 a) 图片服务器FastDFS(Nainx部分) 2. 商品类目选择 2.1. 原型 2.2. 功能分析 展示商 ...
- JAVAEE——宜立方商城02:服务中间件dubbo、工程改造为基于soa架构、商品列表实现
1. 学习计划 第二天:商品列表功能实现 1.服务中间件dubbo 2.工程改造为基于soa架构 3.商品列表查询功能实现. 2. 将工程改造为SOA架构 2.1. 分析 由于宜立方商城是基于soa的 ...
- Visual Studio 2017强制更新方法
Visual Studio 2017强制更新方法 Visual Studio 2017更新时候,用户都是根据消息提示,进行更新.这样做的好处,就是微软可以分批下发升级包,避免集中更新.不过为了早点 ...
- C# String.Format 格式化字符串 数字/时间
首先献给只想知道结果的人 格式化 DateTime 对象 标准 数字 格式化 Int Decimal Float Double 关于这一块一直不是很清楚,MSDN 上也不够清晰. 就花了点时间敲了一下 ...
- C# 集合类-使用
关联性集合类 关联性集合类即我们常说的键值对集合,允许我们通过Key来访问和维护集合. 我们来看一下 .net 为我们提供了哪些泛型的关联性集合类: Dictionary<TKey,TValu ...
- 【BZOJ 3640】JC的小苹果 (高斯消元,概率DP)
JC的小苹果 Submit: 432 Solved: 159 Description 让我们继续JC和DZY的故事. “你是我的小丫小苹果,怎么爱你都不嫌多!” “点亮我生命的火,火火火火火!” 话 ...
- luoguP4466 [国际集训队]和与积 莫比乌斯反演
自然想到枚举\(gcd(a, b)\),不妨设其为\(d\),并且\(a = di, b = dj(a > b)\) 那么\(\frac{ab}{a + b} = \frac{dij}{i + ...
- ZOJ2112 BZOJ1901 Dynamic Rankings 树套树 带修改的区间第k小
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112 树套树,线段树套splay或者主席树套树状数组,我抄了一下hzwer ...
- javascript中的lambda表达式
<!DOCTYPE html> <html> <head> </head> <body> <script> var nubLis ...
- spring---aop(3)---Spring AOP的拦截器链
写在前面 时间断断续续,这次写一点关于spring aop拦截器链的记载.至于如何获取spring的拦截器,前一篇博客已经写的很清楚(spring---aop(2)---Spring AOP的JDK动 ...