Android事件处理第一节(View对Touch事件的处理)
http://ipjmc.iteye.com/blog/1694146
在Android里Touch是很常用的事件,尤其实在自定义控件中,要实现一些动态的效果,往往要对Touch进行处理。Android中主要有3个地方可以处理Touch事件:
一、在View里,有两个回调函数
- public boolean dispatchTouchEvent(MotionEvent ev);
- public boolean onTouchEvent(MotionEvent ev);
二、在ViewGroup里,有三个回调函数
- public boolean dispatchTouchEvent(MotionEvent ev);
- public boolean onInterceptTouchEvent(MotionEvent ev);
- public boolean onTouchEvent(MotionEvent ev);
三、在Activity里,有两个回调函数
- public boolean dispatchTouchEvent(MotionEvent ev);
- public boolean onTouchEvent(MotionEvent ev);
在这三个不同的地方,它们对Touch事件的处理流程很相似,但也有不同的地方。
在本节,就先研究View对Touch的处理过程。首先,Touch事件先到达dispatchTouchEvent(),我们来看看View.dispatchTouchEvent()的源码,这里面涉及到View的onTouchListener,和onTouchEvent()。
- public boolean dispatchTouchEvent(MotionEvent event) {
- if (mInputEventConsistencyVerifier != null) {
- mInputEventConsistencyVerifier.onTouchEvent(event, 0);
- }
- if (onFilterTouchEventForSecurity(event)) {
- //noinspection SimplifiableIfStatement
- ListenerInfo li = mListenerInfo;
- if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
- && li.mOnTouchListener.onTouch(this, event)) {
- return true;
- }
- if (onTouchEvent(event)) {
- return true;
- }
- }
- if (mInputEventConsistencyVerifier != null) {
- mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
- }
- return false;
- }
从源码中,我们可以看出View的onTouchListener和onTouchEvent都是在这里被调用的。如果View的touchListener返回true,dispatchTouchEvent()直接就返回,连onTouchEvent都不会被调用了。只有View没有设置onTouchListener,或者touchListener.onTouch()返回false,才会调用onTouchEvent()。
我们还可以看出,如果onTouchEvent()被执行了的话,dispatchTouchEvent()的返回值就是onTouchEvent()的返回值。事实上,真正起作用的也就是dispatchTouchEvent(),onTouchEvent()只是被dispatchTouchEvent()调用了而已。关于这个返回值的作用,请往下看。
我们需要一些实验,自定义控件还使用之前的画板
- package com.ipjmc.vgdemo;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.Canvas;
- import android.graphics.Paint;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.MotionEvent;
- import android.view.View;
- public class CustomView extends View {
- private static final String TAG = "CustomView";
- private int mLastX, mLastY;
- private int mCurrX, mCurrY;
- private Bitmap mBitmap;
- private Paint mPaint;
- public CustomView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mPaint = new Paint();
- mPaint.setStrokeWidth(6);
- }
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- int width = getWidth();
- int height = getHeight();
- if (mBitmap == null) {
- mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- }
- Canvas tmpCanvas = new Canvas(mBitmap);
- tmpCanvas.drawLine(mLastX, mLastY, mCurrX, mCurrY, mPaint);
- canvas.drawBitmap(mBitmap, 0, 0, mPaint);
- }
- @Override
- public boolean dispatchTouchEvent(MotionEvent event) {
- Utils.log(TAG, "dispatchTouchEvent", event.getAction());
- return super.dispatchTouchEvent(event);
- }
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- mLastX = mCurrX;
- mLastY = mCurrY;
- mCurrX = (int) event.getX();
- mCurrY = (int) event.getY();
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- mLastX = mCurrX;
- mLastY = mCurrY;
- break;
- default:
- break;
- }
- invalidate();
- return true;
- }
- }
我们在画板上画一条线,看一下日志
如果我们把dispatchTouchEvent的返回值改为true,无论onTouchEvent()的返回值是什么,都不影响。
现在,我们把dispatchTouchEvent的返回值,改为false看看会怎么样
- @Override
- public boolean dispatchTouchEvent(MotionEvent event) {
- Utils.log(TAG, "dispatchTouchEvent", event.getAction());
- super.dispatchTouchEvent(event);
- return false;
- }
我们在画板上画一条线,看一下日志
我们可以看到,只在Touch事件是ACTION_DOWN的时候,打印了一条日志,而且画板上也没有画出一条线。这是说明在ACTION_DOWN的时候,如果dispatchTouchEvent返回false,那么这个View就接收不到后面的触屏事件了。
如果我们这样改呢?dispatchTouchEvent()只在ACTION_DOWN的时候,返回true,其他时候返回false。答案是一切又恢复正常了。
- public boolean dispatchTouchEvent(MotionEvent event) {
- Utils.log(TAG, "dispatchTouchEvent", event.getAction());
- super.dispatchTouchEvent(event);
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- return true;
- }
- return false;
- }
可以这样理解。每一个触屏事件都必须是以ACTION_DOWN作为开头,后面跟一系列的ACTION_MOVE,最后再有一个ACTION_UP(或ACTION_CANCEL),标识触屏事件结束。所以Android就在ACTION_DOWN的时候做文章,官方文档对dispatchTouchEvent的返回值的解释是:True if the event was handled by the view, false otherwise。我们可以简单的理解为如果返回true,就说明它需要处理这个事件,就让它接收所有的触屏事件,否则,说明它不用处理,也就不让它接收后续的触屏事件了。
Android事件处理第一节(View对Touch事件的处理)的更多相关文章
- Android:ViewGroup和View的Touch事件
Android中ViewGroup和View中的Touch事件传递机制分析 关键字:GroupView:View:Touch事件 基础知识: onInterceptTouchEvent():在View ...
- Android学习第六弹之Touch事件的处理
在移动开发过程当中,我们经常会遇到手势处理和事件触摸的情况,如果不了解整个事件的处理机制,对于开发的同学和码农是非常痛苦的,但是事件触摸的处理确实是一个非常复杂的过程,细讲起来,估计我都能讲迷糊,这里 ...
- android课程第一节(TextView控件使用)
TextView控件使用 一.TextView基本使用(创建方式) 1.在程序中创建TextView对象 如下代码: @Override protected void onCreate(Bundle ...
- Android Touch事件之一:Touch事件在父ViewGroup和子View之间的传递篇
2015-11-26 17:00:22 前言:Android的Touch事件传递和View的实现紧密相连,因此理解Touch事件的传递,有助于我们更好的理解View的工作原理. 1. 几个重要的方法: ...
- Andriod 从源码的角度详解View,ViewGroup的Touch事件的分发机制
转自:xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/21696315) 今天这篇文章主要分析的是Android的事件分发机制, ...
- Android Touch事件分发过程
虽然网络上已经有非常多关于这个话题的优秀文章了,但还是写了这篇文章,主要还是为了加强自己的记忆吧,自己过一遍总比看别人的分析要深刻得多.那就走起吧. 简单演示样例 先看一个演示样例 : 布局文件 : ...
- 自定义View系列教程07--详解ViewGroup分发Touch事件
深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Andr ...
- 自定义View系列教程06--详解View的Touch事件处理
深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Andr ...
- Android中的Touch事件
Android中的Touch事件处理 主要内容 Activity或View类的onTouchEvent()回调函数会接收到touch事件. 一个完整的手势是从ACTION_DOWN开始,到ACTION ...
随机推荐
- linux 双网卡桥接,实现网卡流量镜像与转发
确认本地是否存在brctl,如果不存在请先安装: 1.确定你的镜像端口,比如eth1: 2.将实际数据通过的端口,比如eth0和镜像端口绑成一个bridge: brctl addbr br0 brct ...
- 突发奇想想学习做一个HTML5小游戏
前言: 最近一期文化馆轮到我分享了,分享了两个,一个是关于童年教科书的回忆,一个是关于免费电子书的.最后我觉得应该会不敌web,只能说是自己在这中间回忆了一下那个只是会学习的年代,那个充满梦想的年代. ...
- Linux-485收发切换延迟的解决方法
[前言] 本文引用各种资料甚多,而引用出处标明并不详细,若有侵权,请联系删除. 转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10381616.html ...
- libtorch初体验
环境 Ubuntu -18.04.1, opencv3.4.0 , python 3.6, cmake 3.5.0, pytorch 1.0. pytorch官网下载对应版本:https://py ...
- spring cloud zuul 传递 header
最近在做一个项目时,发现在网关中调用和在子系统中调用request.getRequestURL()所得到的请求url是不一样的,在网关中得到的是通过域名访问的地址,而在子系统中得到的是网关发起的子系统 ...
- [android] 手机卫士手势滑动切换屏幕
定义手势识别器 获取手势识别器GestureDetector对象,通过new GestureDetector(context,listener),参数:上下文,监听器 匿名内部类实现简单手势监听器Si ...
- centos7使用yum安装mysql 【转】
转自:http://blog.csdn.net/eclothy/article/details/52733891 使用: yum install mariadb* (注意,带星号) 安装好后,启 ...
- 【Java并发编程】19、DelayQueue源码分析
DelayQueue,带有延迟元素的线程安全队列,当非阻塞从队列中获取元素时,返回最早达到延迟时间的元素,或空(没有元素达到延迟时间).DelayQueue的泛型参数需要实现Delayed接口,Del ...
- webpack4 系列教程(三): 多页面解决方案--提取公共代码
这节课讲解webpack4打包多页面应用过程中的提取公共代码部分.相比于webpack3,4.0版本用optimization.splitChunks配置替换了3.0版本的CommonsChunkPl ...
- Vue学习资料
1. {{ msg }}插值表达式. v-text:将数据插入到页面中,没有闪烁问题. v-cloak:通过style属性选择器的方式display:none:防止闪烁问题. v-html:将标签解析 ...