Android:ViewGroup和View的Touch事件
Android中ViewGroup和View中的Touch事件传递机制分析
关键字:GroupView;View;Touch事件
基础知识:
onInterceptTouchEvent():在ViewGroup中定义(View中无该方法),用于拦截手势事件,触发的每个Touch事件都会先调用onInterceptTouchEvent()。
onTouchEvent():分别View中(ViewGroup继承自View,自然包含该方法),用于处理传递到View中的Touch事件。
View中的onTouchEvent()返回true时,表明:当次已经完全消费了该事件,不希望其他回调方法再次处理;反之则返回false。
事件回调过程:当我们手指点击屏幕时候,先调用ACTION_DOWN事件,当onTouchEvent()里返回值是true的时候,onTouchEvent()会继续调用ACTION_UP事件,如果onTouchEvent()里返回值是false,那么onTouch只会调用ACTION_DOWN而不调用ACTION_UP。关于返回值的问题,基本规则很清楚,如果return true,那么表示该方法消费了此次事件,如果return false,那么表示该方法并未处理完全,该事件仍然需要以某种方式传递下去继续等待处理。
Touch事件包含:ACTION_DOWN(getAction()=0),ACTION_UP(getAction()=1),ACTION_MOVE(getAction()=2),ACTION_CANCEL等事件。针对down事件的处理返回值直接影响到后续的move和up事件的接收和传递。
Android SDK对onInterceptTouchEvent()的解释:
由于onInterceptTouchEvent()的机制比较复杂,上面的说明写的也比较复杂,总结一下,基本的规则是:
1. down事件首先会传递到onInterceptTouchEvent()方法;
2. 如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false,那么后续的move, up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最终的目标view的onTouchEvent()处理;
3. 如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move, up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件;
4. 如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一层次的view的onTouchEvent()处理;
5. 如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。
现通过如下的简单实例分析Android中的点击事件:

其中,整个布局是一个自定义ViewGroup,下面的Button同样是自定义View。
整体布局如下:
<com.demo.view.DesignLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.demo.TouchEventDemo" >
<com.demo.view.DesignView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</com.demo.view.DesignLayout>
自定义的ViewGroup为:
package com.demo.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.FrameLayout;
import com.demo.LogUtil;
public class DesignLayout extends FrameLayout {
private static final String TAG = DesignLayout.class.getSimpleName();
public DesignLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DesignLayout(Context context) {
super(context);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// 默认返回false
LogUtil.d(TAG,
"DesignLayout:onInterceptTouchEvent::super.onInterceptTouchEvent(ev)="
+ super.onInterceptTouchEvent(ev));
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// 默认返回false
LogUtil.d(TAG, "DesignLayout:onTouchEvent::super.onTouchEvent(event)="
+ super.onTouchEvent(event));
return super.onTouchEvent(event);
}
}
自定义的View:
package com.demo.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Button;
import com.demo.LogUtil;
public class DesignView extends Button {
private static final String TAG = DesignView.class.getSimpleName();
public DesignView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DesignView(Context context) {
super(context);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// 默认返回true
LogUtil.d(TAG, "DesignView:onTouchEvent::super.onTouchEvent(event)="
+ super.onTouchEvent(event));
return false;
}
}
主体的TouchEventActivity如下:
package com.demo;
import android.app.Activity;
import android.os.Bundle;
public class TouchEventDemo extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
测试结果如下:
Layout中的onInterceptTouchEvent()默认返回的是false,表示不拦截Touch事件,也就是说:Touch事件将传递到View控件中;onTouchEvent(),默认返回的是false;
View中的onTouchEvent()默认返回的是true;
实验一:Layout中onInterceptTouchEvent()默认返回的是false,View的onTouchEvent()返回true,执行以下逻辑:
D/Demo (13207): [DesignLayout] DesignLayout:onInterceptTouchEvent::super.onInterceptTouchEvent(ev)=false
D/Demo (13207): [DesignLayout] onInterceptTouchEvent::MotionEvent.ACTION_DOWN
D/Demo (13207): [DesignView] DesignView:onTouchEvent::super.onTouchEvent(event)=true
D/Demo (13207): [DesignView] DesignView:onTouchEvent::MotionEvent.ACTION_DOWN
D/Demo (13207): [DesignLayout] DesignLayout:onInterceptTouchEvent::super.onInterceptTouchEvent(ev)=false
D/Demo (13207): [DesignLayout] onInterceptTouchEvent::MotionEvent.ACTION_MOVE
D/Demo (13207): [DesignView] DesignView:onTouchEvent::super.onTouchEvent(event)=true
D/Demo (13207): [DesignView] DesignView:onTouchEvent::MotionEvent.ACTION_MOVE
D/Demo (13207): [DesignLayout] DesignLayout:onInterceptTouchEvent::super.onInterceptTouchEvent(ev)=false
D/Demo (13207): [DesignLayout] onInterceptTouchEvent::MotionEvent.ACTION_MOVE
D/Demo (13207): [DesignView] DesignView:onTouchEvent::super.onTouchEvent(event)=true
D/Demo (13207): [DesignView] DesignView:onTouchEvent::MotionEvent.ACTION_MOVE
D/Demo (13207): [DesignLayout] DesignLayout:onInterceptTouchEvent::super.onInterceptTouchEvent(ev)=false
D/Demo (13207): [DesignLayout] onInterceptTouchEvent::MotionEvent.ACTION_UP
D/Demo (13207): [DesignView] DesignView:onTouchEvent::super.onTouchEvent(event)=true
D/Demo (13207): [DesignView] DesignView:onTouchEvent::MotionEvent.ACTION_UP
Layout不拦截Touch事件,传递到子View中;子View消费Touch事件,不会去执行父ViewGroup的onTouchEvent(),本次Touch事件已消费并停止;Layout和子View会多次接收和消费其他Touch事件,比如ACTION_MOVE和ACTION_UP事件。
实验二:让ViewGroup的onInterceptTouchEvent()返回默认的false且onTouchEvent()返回false,但是让View的onTouchEvent()返回false,执行如下逻辑:
D/Demo (13869): [DesignLayout] DesignLayout:onInterceptTouchEvent::super.onInterceptTouchEvent(ev)=false
D/Demo (13869): [DesignLayout] onInterceptTouchEvent::MotionEvent.ACTION_DOWN
D/Demo (13869): [DesignView] DesignView:onTouchEvent::super.onTouchEvent(event)=true
D/Demo (13869): [DesignView] DesignView:onTouchEvent::MotionEvent.ACTION_DOWN
D/Demo (13869): [DesignLayout] DesignLayout:onTouchEvent::super.onTouchEvent(event)=false
D/Demo (13869): [DesignLayout] onTouchEvent::MotionEvent.ACTION_DOWN
Touch事件未被ViewGroup拦截,并传递到底层的View中;View的onTouchEvent()返回false时,表明不消费该Touch事件,会回传到其父ViewGroup的onTouchEvent()中。View里的onTouchEvent只消费了一次点击事件也就是ACTION_DOWN,还没有执行ACTION_UP,然后跑到ViewGroup里又去执行OnTouchEvent事件;此时ViewGroup中onTouchEvent()返回为false,也仅会消费一次ACTION_DOWN事件(或者说,本次Touch事件并未被消费,所以其他的ACTION_MOVE和ACTION_UP事件无法接收)。
点击非Button区域时,也只会去执行ViewGroup的onTouchEvent(),并消费一次ACTION_DOWN。
D/Demo (14433): [DesignLayout] DesignLayout:onInterceptTouchEvent::super.onInterceptTouchEvent(ev)=false
D/Demo (14433): [DesignLayout] onInterceptTouchEvent::MotionEvent.ACTION_DOWN
D/Demo (14433): [DesignLayout] DesignLayout:onTouchEvent::super.onTouchEvent(event)=false
D/Demo (14433): [DesignLayout] onTouchEvent::MotionEvent.ACTION_DOWN
实验三:让ViewGroup的onInterceptTouchEvent()返回默认的false且onTouchEvent()返回true,但是让View的onTouchEvent()返回false,执行如下逻辑:
点击Button区域,并滑动时:
D/Demo (14631): [DesignLayout] DesignLayout:onInterceptTouchEvent::super.onInterceptTouchEvent(ev)=false
D/Demo (14631): [DesignLayout] onInterceptTouchEvent::MotionEvent.ACTION_DOWN
D/Demo (14631): [DesignView] DesignView:onTouchEvent::super.onTouchEvent(event)=true
D/Demo (14631): [DesignView] DesignView:onTouchEvent::MotionEvent.ACTION_DOWN
D/Demo (14631): [DesignLayout] DesignLayout:onTouchEvent::super.onTouchEvent(event)=false
D/Demo (14631): [DesignLayout] onTouchEvent::MotionEvent.ACTION_DOWN
D/Demo (14631): [DesignLayout] DesignLayout:onTouchEvent::super.onTouchEvent(event)=false
D/Demo (14631): [DesignLayout] onTouchEvent::MotionEvent.ACTION_MOVE
D/Demo (14631): [DesignLayout] DesignLayout:onTouchEvent::super.onTouchEvent(event)=false
D/Demo (14631): [DesignLayout] onTouchEvent::MotionEvent.ACTION_UP
Touch事件未被ViewGroup拦截,并传递到底层的View中;View的onTouchEvent()返回false时,表明不消费该Touch事件,会回传到其父ViewGroup的onTouchEvent()中。View里的onTouchEvent只接收一次点击事件也就是ACTION_DOWN(不再接收其他Touch事件),还没有执行ACTION_UP,然后跑到ViewGroup里又去执行OnTouchEvent事件;此时ViewGroup中onTouchEvent()返回为true,也就是消费了本次ACTION_DOWN事件(并表明身份:我能消费Touch事件,以后的事件都由我来消费吧!)。
点击非Button区域,并滑动时:
D/Demo (14631): [DesignLayout] DesignLayout:onInterceptTouchEvent::super.onInterceptTouchEvent(ev)=false
D/Demo (14631): [DesignLayout] onInterceptTouchEvent::MotionEvent.ACTION_DOWN
D/Demo (14631): [DesignLayout] DesignLayout:onTouchEvent::super.onTouchEvent(event)=false
D/Demo (14631): [DesignLayout] onTouchEvent::MotionEvent.ACTION_DOWN
D/Demo (14631): [DesignLayout] DesignLayout:onTouchEvent::super.onTouchEvent(event)=false
D/Demo (14631): [DesignLayout] onTouchEvent::MotionEvent.ACTION_MOVE
D/Demo (14631): [DesignLayout] DesignLayout:onTouchEvent::super.onTouchEvent(event)=false
D/Demo (14631): [DesignLayout] onTouchEvent::MotionEvent.ACTION_UP
每次点击、滑动并抬起时,其消费模式:一次ACTION_DOWN、多次ACTION_MOVE和一次ACTION_UP事件。
实验四:将Layout中的onInterceptTouchEvent()返回值修改为true且onTouchEvent()返回默认值false。点击包含有View的Button区域时,执行下述逻辑:
D/Demo (10417): [DesignLayout] DesignLayout:onInterceptTouchEvent::super.onInterceptTouchEvent(ev)=false
D/Demo (10417): [DesignLayout] onInterceptTouchEvent::MotionEvent.ACTION_DOWN
D/Demo (10417): [DesignLayout] DesignLayout:onTouchEvent::super.onTouchEvent(event)=false
不会执行到View中的onTouchEvent(),表明Touch事件被ViewGroup拦截,会执行ViewGroup的onTouchEvent()(本次只会传递一次ACTION_DOWN事件,不会传递其他事件如:ACTION_MOVE和ACTION_UP)。点击非Button区域时,Logcat打印结果和上述相同。
实验五:实验环境同实验二,不同之处在于ViewGroup的onTouchEvent()返回true,点击包含有View的Button区域时,执行以下逻辑:
D/Demo (15835): [DesignLayout] DesignLayout:onInterceptTouchEvent::super.onInterceptTouchEvent(ev)=false
D/Demo (15835): [DesignLayout] onInterceptTouchEvent::MotionEvent.ACTION_DOWN
D/Demo (15835): [DesignLayout] DesignLayout:onTouchEvent::super.onTouchEvent(event)=false
D/Demo (15835): [DesignLayout] onTouchEvent::MotionEvent.ACTION_DOWN
D/Demo (15835): [DesignLayout] DesignLayout:onTouchEvent::super.onTouchEvent(event)=false
D/Demo (15835): [DesignLayout] onTouchEvent::MotionEvent.ACTION_MOVE
D/Demo (15835): [DesignLayout] DesignLayout:onTouchEvent::super.onTouchEvent(event)=false
D/Demo (15835): [DesignLayout] onTouchEvent::MotionEvent.ACTION_MOVE
D/Demo (15835): [DesignLayout] DesignLayout:onTouchEvent::super.onTouchEvent(event)=false
D/Demo (15835): [DesignLayout] onTouchEvent::MotionEvent.ACTION_UP
不会执行到View中的onTouchEvent(),表明Touch事件被ViewGroup拦截,会执行ViewGroup的onTouchEvent();但不同之处在于:不但会接收到ACTION_DOWN事件,其他事件也会接收到如:ACTION_MOVE和ACTION_UP。
点击非Button区域时,执行以下逻辑:
D/Demo (15835): [DesignLayout] DesignLayout:onInterceptTouchEvent::super.onInterceptTouchEvent(ev)=false
D/Demo (15835): [DesignLayout] onInterceptTouchEvent::MotionEvent.ACTION_DOWN
D/Demo (15835): [DesignLayout] DesignLayout:onTouchEvent::super.onTouchEvent(event)=false
D/Demo (15835): [DesignLayout] onTouchEvent::MotionEvent.ACTION_DOWN
D/Demo (15835): [DesignLayout] DesignLayout:onTouchEvent::super.onTouchEvent(event)=false
D/Demo (15835): [DesignLayout] onTouchEvent::MotionEvent.ACTION_MOVE
D/Demo (15835): [DesignLayout] DesignLayout:onTouchEvent::super.onTouchEvent(event)=false
D/Demo (15835): [DesignLayout] onTouchEvent::MotionEvent.ACTION_UP
D/Demo (15835): [DesignLayout] DesignLayout:onTouchEvent::super.onTouchEvent(event)=false
D/Demo (15835): [DesignLayout] onTouchEvent::MotionEvent.ACTION_MOVE
Android:ViewGroup和View的Touch事件的更多相关文章
- Android事件处理第一节(View对Touch事件的处理)
http://ipjmc.iteye.com/blog/1694146 在Android里Touch是很常用的事件,尤其实在自定义控件中,要实现一些动态的效果,往往要对Touch进行处理.Androi ...
- Android:30分钟弄明白Touch事件分发机制
Touch事件分发中只有两个主角:ViewGroup和View.Activity的Touch事件事实上是调用它内部的ViewGroup的Touch事件,可以直接当成ViewGroup处理. View在 ...
- Android Touch事件之一:Touch事件在父ViewGroup和子View之间的传递篇
2015-11-26 17:00:22 前言:Android的Touch事件传递和View的实现紧密相连,因此理解Touch事件的传递,有助于我们更好的理解View的工作原理. 1. 几个重要的方法: ...
- View,ViewGroup的Touch事件的分发机制
原帖地址:http://blog.csdn.net/xiaanming/article/details/21696315 ViewGroup的事件分发机制 我们用手指去触摸Android手机屏幕,就会 ...
- Andriod 从源码的角度详解View,ViewGroup的Touch事件的分发机制
转自:xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/21696315) 今天这篇文章主要分析的是Android的事件分发机制, ...
- 自定义View系列教程07--详解ViewGroup分发Touch事件
深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Andr ...
- Android Touch事件传递机制 二:单纯的(伪生命周期)
转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在 ...
- Android中的Touch事件
Android中的Touch事件处理 主要内容 Activity或View类的onTouchEvent()回调函数会接收到touch事件. 一个完整的手势是从ACTION_DOWN开始,到ACTION ...
- (转)Android Touch事件传递机制
-----来源:http://www.trinea.cn/android/touch-event-delivery-mechanism/ 介绍Android Touch事件的传递机制. 不少朋友私信问 ...
随机推荐
- 怎样在win7 IIS中部署网站
怎样在win7 IIS中部署网站? IIS作为微软web服务器的平台,可以轻松的部署网站,让网站轻而易举的搭建成功,那么如何在IIS中部署一个网站呢,下面就跟小编一起学习一下吧. 第一步:发布IIS文 ...
- 史上最简单的SpringCloud教程 | 第五篇: 路由网关(zuul)
在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现.服务消费.负载均衡.断路器.智能路由.配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统.一个简答的微服务系统如下图: ...
- 页面注册系统--使用forms表单结合ajax
页面注册系统--使用forms表单结合ajax 在Django中通过forms构建一个表单 1.urls.py 配置路由 from django.conf.urls import url from d ...
- Nancy 返回值详解
简介 Nancy 是一个轻量级的,简单粗暴的framework用来构建基于HTTP的各种服务,兼容.Net和Mono.它的返回值也是多种多样的,适应各种不同的情况.包括Response.AsFile( ...
- [转] webpack之plugin内部运行机制
简介 webpack作为当前最为流行的模块打包工具,几乎所有的主流前端开发框架(React.Vue等)都会将其作为默认的模块加载和打包工具.通过简单的配置项,使用各种相关的loader和plugin, ...
- POJ 1273 Drainage Ditches【最大流模版】
题意:现在有m个池塘(从1到m开始编号,1为源点,m为汇点),及n条有向水渠,给出这n条水渠所连接的点和所能流过的最大流量,求从源点到汇点能流过的最大流量 Dinic #include<iost ...
- [转]Prometheus 与 Grafana 实现服务器运行状态监控
http://flintx.me/2017/12/12/Prometheus%20+%20Grafana%20%E5%AE%9E%E7%8E%B0%E6%9C%8D%E5%8A%A1%E5%99%A8 ...
- [转]GitHub for Windows 安装失败,An error occurred attempting to install github 的解决办法
解决办法: 只需要将 http://github-windows.s3.amazonaws.com/GitHub.application http改为https,然后在IE上打开,安装即可 问题如下 ...
- python全栈开发day67--字段类型、字段属性、ORM回顾
一.回顾总结 https://www.cnblogs.com/maple-shaw/articles/9323320.html 1. 视图 1. CBV 和 FBV from django.views ...
- python全栈开发day66-视图系统、路由系统
一.昨日内容回顾 1. tags 1. for循环 {% for name in name_list %} {{ name }} {% endfor %} {% for name in name_li ...