http://ipjmc.iteye.com/blog/1694146

在Android里Touch是很常用的事件,尤其实在自定义控件中,要实现一些动态的效果,往往要对Touch进行处理。Android中主要有3个地方可以处理Touch事件:

一、在View里,有两个回调函数

  1. public boolean dispatchTouchEvent(MotionEvent ev);
  2. public boolean onTouchEvent(MotionEvent ev);

二、在ViewGroup里,有三个回调函数

  1. public boolean dispatchTouchEvent(MotionEvent ev);
  2. public boolean onInterceptTouchEvent(MotionEvent ev);
  3. public boolean onTouchEvent(MotionEvent ev);

三、在Activity里,有两个回调函数

  1. public boolean dispatchTouchEvent(MotionEvent ev);
  2. public boolean onTouchEvent(MotionEvent ev);

在这三个不同的地方,它们对Touch事件的处理流程很相似,但也有不同的地方。 
        在本节,就先研究View对Touch的处理过程。首先,Touch事件先到达dispatchTouchEvent(),我们来看看View.dispatchTouchEvent()的源码,这里面涉及到View的onTouchListener,和onTouchEvent()。

  1. public boolean dispatchTouchEvent(MotionEvent event) {
  2. if (mInputEventConsistencyVerifier != null) {
  3. mInputEventConsistencyVerifier.onTouchEvent(event, 0);
  4. }
  5. if (onFilterTouchEventForSecurity(event)) {
  6. //noinspection SimplifiableIfStatement
  7. ListenerInfo li = mListenerInfo;
  8. if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
  9. && li.mOnTouchListener.onTouch(this, event)) {
  10. return true;
  11. }
  12. if (onTouchEvent(event)) {
  13. return true;
  14. }
  15. }
  16. if (mInputEventConsistencyVerifier != null) {
  17. mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
  18. }
  19. return false;
  20. }

从源码中,我们可以看出View的onTouchListener和onTouchEvent都是在这里被调用的。如果View的touchListener返回true,dispatchTouchEvent()直接就返回,连onTouchEvent都不会被调用了。只有View没有设置onTouchListener,或者touchListener.onTouch()返回false,才会调用onTouchEvent()。 
        我们还可以看出,如果onTouchEvent()被执行了的话,dispatchTouchEvent()的返回值就是onTouchEvent()的返回值。事实上,真正起作用的也就是dispatchTouchEvent(),onTouchEvent()只是被dispatchTouchEvent()调用了而已。关于这个返回值的作用,请往下看。

我们需要一些实验,自定义控件还使用之前的画板

  1. package com.ipjmc.vgdemo;
  2. import android.content.Context;
  3. import android.graphics.Bitmap;
  4. import android.graphics.Canvas;
  5. import android.graphics.Paint;
  6. import android.util.AttributeSet;
  7. import android.util.Log;
  8. import android.view.MotionEvent;
  9. import android.view.View;
  10. public class CustomView extends View {
  11. private static final String TAG = "CustomView";
  12. private int mLastX, mLastY;
  13. private int mCurrX, mCurrY;
  14. private Bitmap mBitmap;
  15. private Paint mPaint;
  16. public CustomView(Context context, AttributeSet attrs) {
  17. super(context, attrs);
  18. mPaint = new Paint();
  19. mPaint.setStrokeWidth(6);
  20. }
  21. @Override
  22. protected void onDraw(Canvas canvas) {
  23. super.onDraw(canvas);
  24. int width = getWidth();
  25. int height = getHeight();
  26. if (mBitmap == null) {
  27. mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
  28. }
  29. Canvas tmpCanvas = new Canvas(mBitmap);
  30. tmpCanvas.drawLine(mLastX, mLastY, mCurrX, mCurrY, mPaint);
  31. canvas.drawBitmap(mBitmap, 0, 0, mPaint);
  32. }
  33. @Override
  34. public boolean dispatchTouchEvent(MotionEvent event) {
  35. Utils.log(TAG, "dispatchTouchEvent", event.getAction());
  36. return super.dispatchTouchEvent(event);
  37. }
  38. @Override
  39. public boolean onTouchEvent(MotionEvent event) {
  40. mLastX = mCurrX;
  41. mLastY = mCurrY;
  42. mCurrX = (int) event.getX();
  43. mCurrY = (int) event.getY();
  44. switch (event.getAction()) {
  45. case MotionEvent.ACTION_DOWN:
  46. mLastX = mCurrX;
  47. mLastY = mCurrY;
  48. break;
  49. default:
  50. break;
  51. }
  52. invalidate();
  53. return true;
  54. }
  55. }

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

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

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

  1. @Override
  2. public boolean dispatchTouchEvent(MotionEvent event) {
  3. Utils.log(TAG, "dispatchTouchEvent", event.getAction());
  4. super.dispatchTouchEvent(event);
  5. return false;
  6. }

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


        我们可以看到,只在Touch事件是ACTION_DOWN的时候,打印了一条日志,而且画板上也没有画出一条线。这是说明在ACTION_DOWN的时候,如果dispatchTouchEvent返回false,那么这个View就接收不到后面的触屏事件了。 
        如果我们这样改呢?dispatchTouchEvent()只在ACTION_DOWN的时候,返回true,其他时候返回false。答案是一切又恢复正常了。

  1. public boolean dispatchTouchEvent(MotionEvent event) {
  2. Utils.log(TAG, "dispatchTouchEvent", event.getAction());
  3. super.dispatchTouchEvent(event);
  4. if (event.getAction() == MotionEvent.ACTION_DOWN) {
  5. return true;
  6. }
  7. return false;
  8. }

可以这样理解。每一个触屏事件都必须是以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事件的处理)的更多相关文章

  1. Android:ViewGroup和View的Touch事件

    Android中ViewGroup和View中的Touch事件传递机制分析 关键字:GroupView:View:Touch事件 基础知识: onInterceptTouchEvent():在View ...

  2. Android学习第六弹之Touch事件的处理

    在移动开发过程当中,我们经常会遇到手势处理和事件触摸的情况,如果不了解整个事件的处理机制,对于开发的同学和码农是非常痛苦的,但是事件触摸的处理确实是一个非常复杂的过程,细讲起来,估计我都能讲迷糊,这里 ...

  3. android课程第一节(TextView控件使用)

    TextView控件使用 一.TextView基本使用(创建方式) 1.在程序中创建TextView对象 如下代码: @Override protected void onCreate(Bundle ...

  4. Android Touch事件之一:Touch事件在父ViewGroup和子View之间的传递篇

    2015-11-26 17:00:22 前言:Android的Touch事件传递和View的实现紧密相连,因此理解Touch事件的传递,有助于我们更好的理解View的工作原理. 1. 几个重要的方法: ...

  5. Andriod 从源码的角度详解View,ViewGroup的Touch事件的分发机制

    转自:xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/21696315) 今天这篇文章主要分析的是Android的事件分发机制, ...

  6. Android Touch事件分发过程

    虽然网络上已经有非常多关于这个话题的优秀文章了,但还是写了这篇文章,主要还是为了加强自己的记忆吧,自己过一遍总比看别人的分析要深刻得多.那就走起吧. 简单演示样例 先看一个演示样例 : 布局文件 : ...

  7. 自定义View系列教程07--详解ViewGroup分发Touch事件

    深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Andr ...

  8. 自定义View系列教程06--详解View的Touch事件处理

    深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Andr ...

  9. Android中的Touch事件

    Android中的Touch事件处理 主要内容 Activity或View类的onTouchEvent()回调函数会接收到touch事件. 一个完整的手势是从ACTION_DOWN开始,到ACTION ...

随机推荐

  1. springboot aop 自定义注解方式实现完善日志记录(完整源码)

    版权声明:本文为博主原创文章,欢迎转载,转载请注明作者.原文超链接 一:功能简介 本文主要记录如何使用aop切面的方式来实现日志记录功能. 主要记录的信息有: 操作人,方法名,参数,运行时间,操作类型 ...

  2. 浅谈MemCahe

    MemCahe 首先介绍下memcahce的定义:是一个分布式的高速缓存系统,目前被许多网站使用以提升网站的访问速度,尤其对于一些大型的.需要频繁访问数据库的网站访问速度提升效果十分显著. 接下来介绍 ...

  3. 微信公众号开发--.Net Core实现微信消息加解密

    1:准备工作 进入微信公众号后台设置微信服务器配置参数(注意:Token和EncodingAESKey必须和微信服务器验证参数保持一致,不然验证不会通过). 2:基本配置 设置为安全模式 3.代码实现 ...

  4. Apollo源码阅读笔记(一)

    Apollo源码阅读笔记(一) 先来一张官方客户端设计图,方便我们了解客户端的整体思路. 我们在使用Apollo的时候,需要标记@EnableApolloConfig来告诉程序开启apollo配置,所 ...

  5. Git实战手册(二): 标签应用和版本管理

    教程所示图片使用的是 github 仓库图片,墙内朋友请移步原文地址 有空就来看看个人技术小站, 我一直都在 0. 背景介绍 当一个代码仓库进过长时间的迭代,针对不同的时期和需求,必定会有不同的版本. ...

  6. 26个精选的JavaScript面试问题

    译者按: 从各个平台精选整理出26道由浅入深的题目助你面试 原文: Top 26 JavaScript Interview Questions I Wish I Knew 译者: Fundebug 为 ...

  7. 【读书笔记】iOS-设计简单的Frenzic式益智游戏

    如果你决定用UIView动画或Core Animation,一定要编写一些测试用例,模拟游戏可能遇到的要求最高的动画,另外不要忘记播放声音.不要等到最后才增加声音,因为在iPhone上播放音乐和音效确 ...

  8. js动态控制表单表格

    js动态控制表单表格,这里操作只讲,添加一行,删除一行,删除某一行某一列. 直接放代码: <!DOCTYPE html> <html> <head> <met ...

  9. Expo大作战(四十一)【完】--expo sdk 之 Assets,BarCodeScanner,AppLoading

    Expo大作战系列完结! 简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与 ...

  10. C# winform三种定时方法

    1. 直接用winform 的 timers 拖控件进去 代码 public partial class Form1 : Form     {         public Form1()       ...