前言: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控件的更多相关文章

  1. Android中的事件分发机制

    Android中的事件分发机制 作者:丁明祥 邮箱:2780087178@qq.com 这篇文章这周之内尽量写完 参考资料: Android事件分发机制完全解析,带你从源码的角度彻底理解(上) And ...

  2. 【Unity游戏开发】用C#和Lua实现Unity中的事件分发机制EventDispatcher

    一.简介 最近马三换了一家大公司工作,公司制度规范了一些,因此平时的业余时间多了不少.但是人却懒了下来,最近这一个月都没怎么研究新技术,博客写得也是拖拖拉拉,周六周天就躺尸在家看帖子.看小说,要么就是 ...

  3. Android中的事件分发机制总结

    Android 的事件分发机制 一.View的事件分发总结: View的onTouchEvent和OnTouch区别  还是以自定义的TestButton为例. 我们可以通过重写onTouchEven ...

  4. 浅谈Android中的事件分发机制

    View事件分发机制的本质就是就是MotionEvent事件的分发过程,即MotionEvent产生后是怎样在View之间传递及处理的. 首先介绍一下什么是MotionEvent.所谓MotionEv ...

  5. android事件分发机制

    android事件分发机制,给控件设置ontouch监听事件,当ontouch返回true时,他就不会走onTouchEvent方法,要想走onTouchEvent方法只需要返回ontouch返回fa ...

  6. Android为TV端助力 事件分发机制

    android事件分发机制,给控件设置ontouch监听事件,当ontouch返回true时,他就不会走onTouchEvent方法,要想走onTouchEvent方法只需要返回ontouch返回fa ...

  7. Android面试必问!View 事件分发机制,看这一篇就够了!

    在 Android 开发当中,View 的事件分发机制是一块很重要的知识.不仅在开发当中经常需要用到,面试的时候也经常被问到. 如果你在面试的时候,能把这块讲清楚,对于校招生或者实习生来说,算是一块不 ...

  8. Android与javascript中事件分发机制的简单比较

    在前面两篇博客中,我们讨论了Android中的事件分发的相关内容,那么在本篇博客当中,我们就简单探讨一下html或javascript中的事件分发机制,并进行简单的对比. 在前端中,对事件进行绑定有三 ...

  9. Android查缺补漏(View篇)--事件分发机制

    事件分发机制是Android中非常重要的一个知识点,同时也是难点,相信到目前为止很多Android开发者对事件分发机制并没有一个非常系统的认识,当然也包括博主个人在内.可能在平时的开发工作中我们并没有 ...

随机推荐

  1. 使用Unity NGUI-InputField组件输入时发现显示为白色就是看不到字体

    今天在接入android支付宝 SDK时,打包运行时,发现使用Unity NGUI-InputField组件输入时发现显示为白色就是看不到字体,查找一下发现是与android交互存在的问题, 只需在A ...

  2. 华科机考:N阶楼梯上楼

    时间限制:1秒空间限制:32768K 题目描述 N阶楼梯上楼问题:一次可以走两阶或一阶,问有多少种上楼方式.(要求采用非递归) 输入描述: 输入包括一个整数N,(1<=N<90). 输出描 ...

  3. C语言程序设计第一次作业1

    (一)实验总结 1. 圆面积问题 1:求圆面积和周长 (1)输入圆的半径,计算圆的周长和面积. (2) (3) 2:判断闰年 (1)输入一个四位年份,判断其是否是闰年.闰年的判别条件是该年年份能被4整 ...

  4. iOS 定位简单使用

    一.配置 导入库CoreLocation. 2.info.plist配置key NSLocationWhenInUseUsageDescription和NSLocationAlwaysUsageDes ...

  5. Linux下修改主机IP地址、DNS、主机名的三种方法

    使用root用户登录进入linux,打开进去终端 在终端中输入:vi /etc/sysconfig/network-scripts/ifcfg-eth0 (最后的eth0是网卡名,我的是Auto_et ...

  6. sublime text3中设置Emmet输入标签自动闭合

    项目后端前一段时间从C#转成了JAVA,在开发的过程中,由于HTML对标签的语法很宽松,比如这样:<img src="" alt="">在标签的结尾 ...

  7. JSTL标签四种判断语句的用法

    一.条件运算符 ${user.gender==1?'男':'女'} 二.if() <c:if test="${2>1}">code..</c:if> ...

  8. C# 制作屏保(图片位置随机变化)

    最近无所事事,闲着无聊,在网上翻看资料时碰巧看到了屏保制作,根据大神的思路也理解到屏保也不是很难.因此根据我自己的理解,动手谢了一个屏保. 首先,打开VS2010创建一个Windows窗体应用程序,名 ...

  9. Java经典设计模式之五大创建型模式(附实例和详解)

    一.概况 总体来说设计模式分为三大类: (1)创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. (2)结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥 ...

  10. linux:关于Linux系统中 CPU Memory IO Network的性能监测

    我们知道:系统优化是一项复杂.繁琐.长期的工作.通常监测的子系统有以下这些:CPUMemoryIO Network 下面是常用的监测工具 Linux 系统包括很多子系统(包括刚刚介绍的CPU,Memo ...