安卓中的事件分发机制之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开发者对事件分发机制并没有一个非常系统的认识,当然也包括博主个人在内.可能在平时的开发工作中我们并没有 ...
随机推荐
- RHEL 7修改ssh默认端口号
RHEL7修改默认端口号(默认port22)初次安装系统完毕后默认情况下系统已经启动了sshd服务当然我们也可以先进行检查: 步骤1,检查是否已安装ssh服务 步骤2,检查服务是否已开启 如上图所示显 ...
- 110个oracle常用函数总结
. ASCII 返回与指定的字符对应的十进制数; SQL) zero,ascii( ) space from dual; A A ZERO SPACE --------- --------- ---- ...
- Unity中使用射线查询MeshCollider背面的方法
之前遇到一个问题要从MeshCollider背面方向发出射线,直至检测到该射线与MeshCollider的相交点为止. 后来我用双面MeshCollider的方法解决了http://www.cnblo ...
- python笔记十(列表生成式、字典生成式、生成器、生成器的并行)
一.列表生成式 列表生成式就是python设置的可以用来可以生成列表的. 如要生成一个0-9的列表我们可以通过以下代码实现: >>> list(range(10)) [0, 1, 2 ...
- JavaScript 代码规范
所有的 JavaScript 项目适用同一种规范. JavaScript 代码规范 代码规范通常包括以下几个方面: 变量和函数的命名规则 空格,缩进,注释的使用规则. 其他常用规范-- 规范的代码可以 ...
- 0428-css样式
一.CSS样式表 引入的三种方式1.内联样式:标签内部 style2.内嵌样式:<head></head>标签内部(<style></sty ...
- Java第2次实验提纲(Java基本语法与类库)
1. 使用Git克隆(clone)项目到你的Eclipse项目中 见以下参考资料中的3 从码云将项目clone到你的电脑 重要提示: 使用Git来管理你的代码以后,当你在本机Eclipse项目中开始编 ...
- Openstack: Single node Installation and External Network Accessing Configuration Guide
Summary of installation Step 0: Prerequisites Step 1: Create Openstack hostsystem Step 2: Config Ope ...
- Bootstrap3 表格-鼠标悬停
通过添加 .table-hover 类可以让 <tbody> 中的每一行对鼠标悬停状态作出响应. <table class="table table-hover" ...
- 自定义一个仿Spinner
两个布局文件: adpter_list.xml <?xml version="1.0" encoding="utf-8"?> <LinearL ...