安卓中的事件分发机制之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开发者对事件分发机制并没有一个非常系统的认识,当然也包括博主个人在内.可能在平时的开发工作中我们并没有 ...
随机推荐
- teachable-machine:探索机器学习如何工作,浏览器中实时浏览
教学机器是一个实验,让所有人都非常方便的探索机器学习,在浏览器中实时浏览,不需要编程.学习更多实验,然后亲自尝试它 访问:https://teachablemachine.withgoogle.com ...
- swift 初始化
知识点总结: 1.结构体 1.1.默认初始化方法:1.空初始化方法:2.成员初始化方法 struct Person{ var name = "tom" var age = } le ...
- AQS简简单单过一遍
前言 回顾前面: 多线程三分钟就可以入个门了! Thread源码剖析 多线程基础必要知识点!看了学习多线程事半功倍 Java锁机制了解一下 只有光头才能变强! 本来我是打算在这章节中写Lock的子类实 ...
- localStorage存储数组以及取数组方法
var weekArray = ['周一'.'周二'.'周三'.'周四'.'周五']; //存: localStorage.setItem('weekDay',JSON.stringify(weekA ...
- node之子线程child_process模块
node.js是基于单线程模型架构,这样的设计可以带来高效的CPU利用率,但是无法却利用多个核心的CPU,为了解决这个问题,node.js提供了child_process模块,用于新建子进程,子进程的 ...
- ActiveMQ消息传递的两种方式
1.什么是ActiveMQ? ActiveMQ是apache提供的开源的,实现消息传递的一个中间插件,可以和spring整合,是目前最流行的开源消息总线,ActiveMQ是一个完全支持JMS1.1和J ...
- COS对象存储服务的使用
---------------------------------------------------------------------------------------------[版权申明:本 ...
- MySQL系列教程(三)
mySQL集群(cluster) 这一章,我根本不打算写,因为mySQL 的 官方Cluster方案基本上都是bullshit,尤其是它的官方集群方案,竟然都无人维护了,而且mySQL集群完全可以用眼 ...
- RunLoop总结:RunLoop 与GCD 、Autorelease Pool之间的关系
如果在面试中问到RunLoop相关的知识,很有可能也会问到RunLoop与GCD.Autorelease Pool有没有关系,哪些地方用到了GCD.Autorelease Pool等. So,本文就总 ...
- Android Lollipop 5.0 经典新特性回顾
*Tamic 专注移动开发! 更多文章请关注 http://blog.csdn.net/sk719887916 虽然Android已到了7.0 ,但是我们还是不能忘怀视觉革命性改变的5.0,今天回顾下 ...