在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);}@Overrideprotected 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);}@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {Utils.log(TAG, "dispatchTouchEvent", event.getAction());return super.dispatchTouchEvent(event);}@Overridepublic 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;}}

我们在画板上画一条线,看一下日志

Android事件处理第一节(View对Touch事件的处理)_第1张图片

如果我们把dispatchTouchEvent的返回值改为true,无论onTouchEvent()的返回值是什么,都不影响。

现在,我们把dispatchTouchEvent的返回值,改为false看看会怎么样

@Overridepublic 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,就说明它需要处理这个事件,就让它接收所有的触屏事件,否则,说明它不用处理,也就不让它接收后续的触屏事件了。

更多相关文章

  1. Android UI事件处理[isInTouchMode()]
  2. android:动态创建多个按钮 并给每个按键添加监听事件
  3. 2011.06.23——— android 事件处理机制
  4. C语言函数以及函数的使用
  5. Android 如何才能捕获系统的恢复出厂设置事件
  6. Android onClick事件三种实现方法
  7. Android中Preference的使用以及监听事件分析

随机推荐

  1. android 过滤掉系统 安装的应用
  2. android 键值控制显示屏 TP调试
  3. android 按钮效果的两种实现方法
  4. android animation的应用实例
  5. Android XML文档解析(一)——SAX解析
  6. Android开发环境安装配置
  7. 安卓应用最简单做到沉浸式
  8. Android 属性动画实现的扇形菜单效果
  9. android > 搭建 cordova 环境
  10. Android HandlerThread 使用介绍及简单解