`
ipjmc
  • 浏览: 707412 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Android事件处理第一节(View对Touch事件的处理)

阅读更多
        在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,就说明它需要处理这个事件,就让它接收所有的触屏事件,否则,说明它不用处理,也就不让它接收后续的触屏事件了。
  • 大小: 62.7 KB
  • 大小: 9.7 KB
分享到:
评论
2 楼 ipjmc 2013-07-26  
woyaowenzi 写道
实际上,在将DOWN事件一层层分发到View之前,会先走到其Parent的事件分发,如果View的dispatchTouchEvent返回true,那么,就说明,我们在事件分发的时候,找到了一个合适的Target,当下次再分发MOVE或者UP事件时,发现已经有了这个Target,那么就会直接将事件分发到该Target,即我们处理事件的View。如果dispatchTouchEvent返回false,那就说明我们的这个View对该事件不感兴趣,会交给它的Parent处理,如果parent感兴趣,那下次分发时,就分发到Parent上面去了,反之,如果Parent也不感兴趣,那就是往上层层路由,往上抛出这个事件。

是这样
1 楼 woyaowenzi 2013-07-25  
实际上,在将DOWN事件一层层分发到View之前,会先走到其Parent的事件分发,如果View的dispatchTouchEvent返回true,那么,就说明,我们在事件分发的时候,找到了一个合适的Target,当下次再分发MOVE或者UP事件时,发现已经有了这个Target,那么就会直接将事件分发到该Target,即我们处理事件的View。如果dispatchTouchEvent返回false,那就说明我们的这个View对该事件不感兴趣,会交给它的Parent处理,如果parent感兴趣,那下次分发时,就分发到Parent上面去了,反之,如果Parent也不感兴趣,那就是往上层层路由,往上抛出这个事件。

相关推荐

    android事件分发机制Demo

    - **事件向上冒泡**: 如果当前View不消费此事件(即onTouchEvent()返回false),事件会沿着ViewGroup的层级结构向上传递,直到找到第一个处理事件的View或者到达根视图。 - **事件向下分发**: ViewGroup在接收到...

    android事件分发机制

    1. **触摸事件的第一入口**:触摸事件首先被Activity的顶层 `ViewGroup` 接收,即 `dispatchTouchEvent` 方法。 ```java public boolean dispatchTouchEvent(MotionEvent ev) { if (actionMasked == MotionEvent...

    android中处理各种触摸事件

    2. **onDoubleTapEvent(MotionEvent e)**:此方法在双击事件的任一部分发生时被调用,包括第一次触摸按下、抬起及第二次触摸按下。根据`e.getAction()`可以判断具体是哪个阶段。 3. **onDown(MotionEvent e)**:此...

    Android事件分发机制

    - 如果父View不拦截事件,事件会直接传递给第一个可点击或长按的子View。 - 如果父View拦截事件,那么子View将不会收到事件。 7. **事件消耗**: - 当一个View处理了ACTION_DOWN事件,那么后续的ACTION_MOVE和...

    Android事件分发机制(三)事件分发和消费

    本文将详细解析Android事件分发机制的第三部分:事件分发和消费,帮助开发者深入理解这一关键过程。 事件分发主要包括两个阶段:事件传播和事件消费。当用户在屏幕上进行触摸操作时,Android会生成一个MotionEvent...

    android4.0按键处理

    - 第一种方法是尝试通过设置系统UI标志来隐藏导航栏,但`View.SYSTEM_UI_FLAG_HIDE_NAVIGATION`和`View.SYSTEM_UI_FLAG_SHOW_FULLSCREEN`在某些版本中可能无效。 - 第二种方法是通过JNI访问Linux内核的framebuffer...

    Android的Touch事件处理机制介绍

    总结来说,Android的Touch事件处理机制通过层层传递和拦截,确保了对用户触摸行为的精确响应。理解这一机制对于开发高效且用户友好的应用至关重要,尤其是在涉及复杂布局和多点触摸功能时。开发者可以根据需要在不同...

    android悬浮框的onTouch和onClick事件同时存在

    当一个触摸事件发生时,事件会从顶级父View开始向下传递,直到找到第一个愿意接收它的View。在这个过程中,View有机会通过`onTouchEvent()`方法处理事件。如果`onTouchEvent()`返回`true`,表示该View已经完全处理了...

    Android自定义View源码

    这是View绘制流程的第一步,需要按照MeasureSpec规则来计算尺寸。 3. **布局(Layout)**:在`onLayout()`方法中,根据测量结果设置子视图的位置。 4. **绘制(Draw)**:通过重写`onDraw()`方法,使用Canvas对象进行...

    Android-shijian-chuli.zip_android

    本资源"Android-shijian-chuli.zip"提供了一套针对新手的Android事件处理教程,尤其对第3章"Android的事件处理"进行了详细讲解。以下是关于Android事件处理的一些核心知识点: 1. **事件监听器(Event Listeners)*...

    Android 自定义View实现单击和双击事件的方法

    if (0 == mInTouchEventCount.touchCount) // 第一次按下时,开始统计 postDelayed(mInTouchEventCount, 500); break; case MotionEvent.ACTION_UP: mInTouchEventCount.touchCount++; if (mInTouchEventCount....

    Android实现支持所有View的通用的下拉刷新控件

    4. **触摸事件处理**:通过重写onTouchEvent()方法,监听用户的滑动手势。当用户下拉时,调整header和target的位置,同时根据滑动状态更新Header的状态。 5. **动画效果**:在刷新过程中,可能需要添加平滑的动画...

    【Android基础】(11)多点触摸交互处理

    1. `onTouchEvent(MotionEvent event)`:这是Android中处理触摸事件的主要方法,位于`View`类中。开发者可以通过重写此方法来处理单点或多点触摸事件。`MotionEvent`对象的`getActionMasked()`和`getActionIndex()`...

    丰富多彩的Android onTouch事件.doc

    在Android开发中,触摸事件处理是非常关键的一部分,特别是在创建用户交互丰富的应用时。`onTouch`事件是Android UI系统中的核心事件,它涉及到用户与屏幕的直接交互。本篇文章将详细探讨Android的`onTouch`事件,...

    Android基础篇-Button学习

    首先,我们来看第一种绑定监听器的方式:通过XML属性。在布局文件中,Button可以使用`android:onClick`属性直接指定点击事件的处理方法。例如: ```xml android:id="@+id/myButton" android:layout_width="wrap_...

    slidingmenu侧滑菜单点击事件案例

    在Android应用开发中,SlidingMenu是一个非常流行的库,它为应用程序提供了类似原生Google应用的侧滑导航体验。这个库允许用户从屏幕边缘向内滑动以展示一个隐藏的菜单,增强了用户的交互性。本案例主要关注的是如何...

    Android 多点触控实例源码.rar

    3. **GestureDetector**:为了简化触摸事件处理,Android提供了`GestureDetector`类。它可以检测常见的手势,如滑动、点击等。对于多点触控,我们可以自定义`GestureDetector.OnMultiTouchListener`,重写`...

    Android 的触摸事件详解及示例代码

    总结起来,Android 触摸事件处理是一个复杂的流程,涉及到事件的捕获、拦截和传递。`onInterceptTouchEvent()` 和 `onTouchEvent()` 方法控制了事件的流向,而 `GestureDetector` 则为开发者提供了识别多种手势的...

    Android开发艺术探索.任玉刚(带详细书签).pdf

    第一,介绍Android开发者不容易掌握的一些知识点;第二,结合Android源代码和应用层开发过程,融会贯通,介绍一些比较深入的知识点;第三,介绍一些核心技术和Android的性能优化思想。 第1章 Activity的生命周期和...

    android支持多点触摸的DEMO

    通过研究和修改源代码,开发者可以深入理解Android的触摸事件处理机制,并将其应用到自己的应用程序中,创造出更加丰富的用户交互体验。在Eclipse中打开并运行这个项目,你可以亲自体验和调试多点触摸的实现过程,...

Global site tag (gtag.js) - Google Analytics