安卓中的事件分发机制之View控件
前言:Android 中与 Touch 事件相关的方法包括:dispatchTouchEvent(MotionEvent ev)、onInterceptTouchEvent(MotionEvent ev)、onTouchEvent(MotionEvent ev);能够响应这些方法的控件包括:ViewGroup、View、Activity。继承ViewGroup的大多是容器控件,如LinearLayout等,而继承View的大部分是显示控件比如TextView,ImageView等(当然,ViewGroup本身是继承View的),显示控件没有onInterceptTouchEvent。
我们知道,如果要给一个按钮注册一个点击事件,则代码如下:
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("TAG", "onClick execute");
}
});
我们还知道,如果要给一个按钮注册一个触摸事件,则代码如下:
button.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("TAG", "onTouch execute, action " + event.getAction());
return false;
}
});
但是当这两个事件同时注册,则那个事件会先被执行呢?我们通过运行测试结果如下:
可以看到,onTouch事件先执行的,然后才执行的onClick事件,而且onTouch事件执行了两次,这是因为触摸事件的响应动作比点击多多了,当你触摸一个控件时至少会经过A,CTION_DOWN和ACTION_UP,所以通过运行结果我们可以知道:当触摸与点击同时注册到一个控件上时,会先执行onTouch然后执行onClick事件。
但是聪明的你可能就会想到,如果我在滑动一个控件的时候,最终会执行onClick方法,岂不是会导致onClick方法中的代码被执行,如:QQ中的LIstView可以向左滑动显示出删除该条目按钮,点击该item可以进入到chatActivity中查看会话,这样岂不当滑动时最终会执行onClick进入到chatActivity中,这明显不符合使用逻辑,能想到这说明你是一个爱思考的人,安卓设计人员早就帮我们考虑到了当onTouch与onClick同时注册时如何控制它们的运行流程,正如你所看到的,onTouch方法是有返回值的,在上述代码中我们采用的是IDE自动生成的代码,默认返回的是false。我们把它的返回值改为true,然后再运行上述程序,结果如下:
可以看到,这次只执行了onTouch方法,而没执行onClick,讲到这就必须提一个概念:安卓中的事件分发机制。可以理解为当在一个控件注册的onTouch方法中返回true的时候,将不会执行该控件注册的onClick事件。为何是这样的呢?这就需要从源码中找答案了。
首先我们知道,当触摸一个控件时,触摸动作会被Activity捕获到,调用Activity的dispathTouchEVent,然后会执行该控件的dispatchTouchEvent,接着执行控件的onTouch方法(如果注册了的话),带onTouch执行完,如果返回值为false,如上述情形,则
会把touch传递给onTouchEvent,注意最后在onTouchEvent中还调用了onClick方法。具体流程图示如下:
基于上述的分析,我们先看看View中的dispatchTouchEvent源码,如下:
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
可以看到代码非常简洁,就是一个if语句判断一个逻辑是否满足,如果满足则返回true,否则返回onTouchEvent(event),那么该逻辑的作用是什么呢?其实就是是否执行下面的onTouchEvent方法,在这个逻辑中存在三个条件,下面我们一个一个分析:
第一个条件:mOnTouchListener != null ,那我们怎么知道mOnTouchListener 是否为null呢,这就要看mOnTouchListener 是在哪里被赋值,其实是在View类的setOnTouchListener中,代码如下:
public void setOnTouchListener(OnTouchListener l) {
mOnTouchListener = l;
}
所以自然就知道,如果该控件注册了onTouch事件,则 mOnTouchListener 的值就不会为null。
再来看第二个条件:mViewFlags & ENABLED_MASK) == ENABLED,顾名思义就是判断该控件是否可以enable,在上述情形中我们用到的是button控件,默认是enable的,所以该值恒为true。
最后看第三个条件:mOnTouchListener.onTouch(this, event),很明显就是去调用onTouch方法,所以如果onTouch方法返回true,则该参数为true,否则为false,整个if的逻辑判断语句为假,会执行下面的return onTouchEvent(event)方法。
这样也就从源码的角度解释了上面我们测试的运行结果,现总结如下:
1当我们给一个控件同时注册onTouch与onClick的话,则onTouch会先执行,且执行流程按照如下顺序:控件所在布局的dispatchTouchEvent------>控件的dispatchTouchEvent------->控件的onTouch-------->控件的onTouchEvent-------->控件的onClcik。
2如果在触摸一个控件的时候,要屏蔽掉onClick则需要在注册的onTouchListener的onTouch中返回true,这样dispatchTouchEvent中的if语句第三个条件为true,这样就会直接返回true,不会执行onTouchEvent(event).
3onTouch能够得到执行需保证两个前提条件,第一mOnTouchListener的值不能为空,第二当前点击的控件必须是enable的。如果控件是非enable的,那么给它注册onTouch事件将永远得不到执行。对于这一类控件,如果我们想要监听它的touch事件,则必须通过在该控件中重写onTouchEvent方法来实现。
4.通过上述分析,我们可以推断出onClick是在onTouchEvent中执行的。
安卓中的事件分发机制之View控件的更多相关文章
- Android中的事件分发机制
Android中的事件分发机制 作者:丁明祥 邮箱:2780087178@qq.com 这篇文章这周之内尽量写完 参考资料: Android事件分发机制完全解析,带你从源码的角度彻底理解(上) And ...
- 【Unity游戏开发】用C#和Lua实现Unity中的事件分发机制EventDispatcher
一.简介 最近马三换了一家大公司工作,公司制度规范了一些,因此平时的业余时间多了不少.但是人却懒了下来,最近这一个月都没怎么研究新技术,博客写得也是拖拖拉拉,周六周天就躺尸在家看帖子.看小说,要么就是 ...
- Android中的事件分发机制总结
Android 的事件分发机制 一.View的事件分发总结: View的onTouchEvent和OnTouch区别 还是以自定义的TestButton为例. 我们可以通过重写onTouchEven ...
- 浅谈Android中的事件分发机制
View事件分发机制的本质就是就是MotionEvent事件的分发过程,即MotionEvent产生后是怎样在View之间传递及处理的. 首先介绍一下什么是MotionEvent.所谓MotionEv ...
- android事件分发机制
android事件分发机制,给控件设置ontouch监听事件,当ontouch返回true时,他就不会走onTouchEvent方法,要想走onTouchEvent方法只需要返回ontouch返回fa ...
- Android为TV端助力 事件分发机制
android事件分发机制,给控件设置ontouch监听事件,当ontouch返回true时,他就不会走onTouchEvent方法,要想走onTouchEvent方法只需要返回ontouch返回fa ...
- Android面试必问!View 事件分发机制,看这一篇就够了!
在 Android 开发当中,View 的事件分发机制是一块很重要的知识.不仅在开发当中经常需要用到,面试的时候也经常被问到. 如果你在面试的时候,能把这块讲清楚,对于校招生或者实习生来说,算是一块不 ...
- Android与javascript中事件分发机制的简单比较
在前面两篇博客中,我们讨论了Android中的事件分发的相关内容,那么在本篇博客当中,我们就简单探讨一下html或javascript中的事件分发机制,并进行简单的对比. 在前端中,对事件进行绑定有三 ...
- Android查缺补漏(View篇)--事件分发机制
事件分发机制是Android中非常重要的一个知识点,同时也是难点,相信到目前为止很多Android开发者对事件分发机制并没有一个非常系统的认识,当然也包括博主个人在内.可能在平时的开发工作中我们并没有 ...
随机推荐
- 什么是Hash?
什么是Hash? Hash中文翻译为散列,又成为"哈希",是一类函数的统称,其特点是定义域无限,值域有限.把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换 ...
- (转)FIDDER教程
Fiddler是最强大最好用的Web调试工具之一,它能记录所有客户端和服务器的http和https请求,允许你监视,设置断点,甚至修改输入输出数据. 使用Fiddler无论对开发还是测试来说,都有很大 ...
- 浏览器控制台调试json数据
var str ='{"code":0,"message":"","systemTime":"2017-10- ...
- 关于一些基础的Java问题的解答(一)
学习一门语言基础是非常重要的,因此本文总结了一些常见的Java基础问题的解答,希望可以帮到大家. 1. 九种基本数据类型的大小,以及他们的封装类. 9种基本数据类型 基本类型 包装类型 大小 bool ...
- ubuntu 下查看caj文件
知网的学位论文只有CAJ版,而我又偏偏使用Ubuntu,所以就有了这篇文章. 前端时间发现第一种方法在ubuntu 16 上不行, 请使用第二种方法. 第一种方法: 环境:Ubuntu 14.04 6 ...
- leetcode之Find All Numbers Disappeared in an Array
问题来源:Find All Numbers Disappeared in an Array 很久没有刷题了,感觉大脑开始迟钝,所以决定重拾刷题的乐趣.一开始不要太难,选一些通过率高的题目做,然后就看到 ...
- Android音频焦点处理相关的方法
有这么一种场景:你打开qq音乐.优酷客户端.视频播放的时候.这个时候突然来电显示了,此时所有的MediaPlayer相关的服务或者响应都进入"休眠"状态.那么,这个功能是怎么实现的 ...
- linuxsvn源代码版本库建立
linuxsvn源代码版本库建立 下面就要建立代码的版本库做描述: 1. 安装svn版本服务器端 yum install subversion 从镜像下载安装svn服务器端,我们服务器已经安装 ...
- [ExtJS5学习笔记]第三十二节 sencha extjs 5与struts2的ajax交互配置
本文地址:http://blog.csdn.net/sushengmiyan/article/details/43487751 本文作者:sushengmiyan ------------------ ...
- Android Multimedia框架总结(一)MediaPlayer介绍之状态图及生命周期
请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52349221 前言:从本篇开始,将进入Multimedia框架,包含 ...