Android Touch事件总结 一

说明:本博客为原创,转载请注明出处 CSDN-ANDROID 笔记栈
由于作者水平有限,错误在所难免,请见谅,可以留言,本人会及时改正


索引

  • Activity View TouchEvent
  • 传递关系图
  • Demo


Android Touch事件主要有三个方法:
dispatchTouchEvent(分发): Touch事件的入口方法
onInterceptTouchEvent(拦截):ViewGroup拦截事件,不传递给子View
onTouchEvent(处理):是否消费事件

ActivityView都可以处理TouchEvent事件,Activity是所有事件的入口

TouchEvent 事件是从上而下,从外而内开始传递

Activity(window、DecorView) -> ViewGroup -> View

Activity View TouchEvent

事件 dispatchTouchEvent onInterceptTouchEvent onTouchEvent
Activity ×
ViewGroup
View ×

1.分发事件

public boolean dispatchTouchEvent(MotionEvent ev)
{
    return true; // true,MotionEvent已被消费
    // 不调用**super.dispatchTouchEvent()**方法,其他两个方法是不会被调用的!
    // 该方法返回false,代表没有View对该事件进行消费,后续事件将不会被分发给你当前View。
    // super.dispatchTouchEvent()返回结果是根据子View的dispatchTouchEvent方法或者当前View的onTouchEvent方法的返回结果而决定的。
    // 在ViewGroup中,根据特定的排列顺序遍历子Child,调用子View的dispatchTouchEvent的方法来实现事件的分发。
    // (Actvity 永远接收dispatchTouchEvent事件)
}

-如果TouchEvent事件在传递过程中,没有View/ViewGroup对“DOWN”事件进行消费,后续TouchEvent事件(MOVE,UP,CANCEL等)只会被分发到Activity中。

2.拦截事件

public boolean onInterceptTouchEvent(MotionEvent ev)
{
    return true; // true,MotionEvent被当前ViewGroup拦截
    //不会传递给子View的dispatchTouchEvent(),ViewGroup的onTouchEvent()会被调用。
    //这个方法,SDK文档中有如下说明:(翻译的水平有限,请见谅)
    //1.在这个方法中可以接收“DOWN”事件
    //2....
    //3.这个方法返回false,后续事件将会先传递到该方法,随后传到后onTouch方法中
    //4.这个方法返回true,你将不会接收到如下事件:目标View将会接收到一个CANCEL事件,所有的后续事件将会被传递到onTouchEvnet方法中,该方法将不再接收事件
}

onInterceptTouchEvent不是很好理解,可以参考这篇博文:Android 触摸事件机制(四) ViewGroup中触摸事件详解

3.处理事件

public boolean onTouchEvent(MotionEvent ev)
{
    return true; // true,MotionEvent被消费
}

传递关系图

Android Touch事件总结 一_第1张图片

ViewGroup中的onInterceptTouchEvent方法,在Action为“DOWN”的时候或者ViewGroup子View有消费TouchEvnet事件的时候(可能有多个子View对TouchEvnet事件进行相应,这些View组成了TouchTarget链表)会被调用


Demo

GitHub地址: GitHub
环境: Windows7+JAVA8
IDE: AndroidStdio2.2.2
compileSdkVersion:24
测试设备:Nexus5(6.0.1)

Demo中存在多个示例,请在Manifest中更改启动项。

自定义DLFrameLayout继承与FrameLayout,自定义DLView继承与View

分别重载Touch事件的方法,输出日志,代码如下:

 @Override
    public boolean dispatchTouchEvent(MotionEvent ev)
    {
        DLDebug.info(TAG, "dispatchTouchEvent: " + TouchEventHelper.parseAction((ev.getActionMasked())));//输出日志

        boolean dispatchTouchEvent = mDispatchTouchEvent;

        if (mSuperDispatchTouchEvent)//是否调用super方法
        {
            dispatchTouchEvent = super.dispatchTouchEvent(ev) || mDispatchTouchEvent;
        }

        DLDebug.info(TAG, "dispatchTouchEvent: " + dispatchTouchEvent);//输出日志,true/false

        return dispatchTouchEvent;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev)
    {
        DLDebug.info(TAG, "onInterceptTouchEvent: " + TouchEventHelper.parseAction((ev.getActionMasked())));

        boolean onInterceptTouchEvent = mInterceptTouchEvent;

        if (mSuperInterceptTouchEvent)
        {
            onInterceptTouchEvent = super.onInterceptTouchEvent(ev) || mInterceptTouchEvent;
        }

        DLDebug.info(TAG, "onInterceptTouchEvent: " + onInterceptTouchEvent);

        return onInterceptTouchEvent;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev)
    {
        DLDebug.info(TAG, "onTouchEvent: " + TouchEventHelper.parseAction((ev.getActionMasked())));

        boolean onTouchEvent = mTouchEvent;

        if (mSuperTouchEvent)
        {
            onTouchEvent = super.onTouchEvent(ev) || mTouchEvent;
        }

        DLDebug.info(TAG, "onTouchEvent: " + onTouchEvent);

        return onTouchEvent;
    }
  • 验证结果
  • 如果自定义View所有方法都返回false,那么后续事件不会被传递到View或者ViewGroup中,只会被传递到Activity中
  • 输出日志如下:
12-05 15:10:35.440  V/DL_MainActivity: dispatchTouchEvent: DOWN
12-05 15:10:35.440  I/DL_DLFrameLayout: dispatchTouchEvent: DOWN
12-05 15:10:35.440  I/DL_DLFrameLayout: onInterceptTouchEvent: DOWN
12-05 15:10:35.440  I/DL_DLFrameLayout: onInterceptTouchEvent: false
12-05 15:10:35.440  D/DL_DLView: dispatchTouchEvent: DOWN
12-05 15:10:35.441  D/DL_DLView: onTouchEvent: DOWN
12-05 15:10:35.441  D/DL_DLView: onTouchEvent: false
12-05 15:10:35.441  D/DL_DLView: dispatchTouchEvent: false
12-05 15:10:35.441  I/DL_DLFrameLayout: onTouchEvent: DOWN
12-05 15:10:35.441  I/DL_DLFrameLayout: onTouchEvent: false
12-05 15:10:35.441  I/DL_DLFrameLayout: dispatchTouchEvent: false
12-05 15:10:35.441  V/DL_MainActivity: onTouchEvent: DOWN
12-05 15:10:35.441  V/DL_MainActivity: onTouchEvent: false
12-05 15:10:35.441  V/DL_MainActivity: dispatchTouchEvent: false
12-05 15:10:35.634  V/DL_MainActivity: dispatchTouchEvent: MOVE
12-05 15:10:35.634  V/DL_MainActivity: onTouchEvent: MOVE
12-05 15:10:35.634  V/DL_MainActivity: onTouchEvent: false
12-05 15:10:35.634  V/DL_MainActivity: dispatchTouchEvent: false
....
12-05 15:10:36.021  V/DL_MainActivity: dispatchTouchEvent: UP
12-05 15:10:36.021  V/DL_MainActivity: onTouchEvent: UP
12-05 15:10:36.021  V/DL_MainActivity: onTouchEvent: false
12-05 15:10:36.021  V/DL_MainActivity: dispatchTouchEvent: false
// 根据日志可以看出,后续的MOVE/UP事件没有传递到自定义View中。
  • 验证结果
  • 如果ViewGroup onInterceptTouchEvent()中返回true,并且onTouchEvent()中也返回true,那么事件不会被传递到子View中,并且能接收后续事件。
  • 输入日志如下:

    
    12-05 15:38:03.241  V/DL_MainActivity: dispatchTouchEvent: DOWN
    12-05 15:38:03.241  I/DL_DLFrameLayout: dispatchTouchEvent: DOWN
    12-05 15:38:03.241  I/DL_DLFrameLayout: onInterceptTouchEvent: DOWN
    12-05 15:38:03.241  I/DL_DLFrameLayout: onInterceptTouchEvent: true
    12-05 15:38:03.241  I/DL_DLFrameLayout: onTouchEvent: DOWN
    12-05 15:38:03.241  I/DL_DLFrameLayout: onTouchEvent: true
    12-05 15:38:03.241  I/DL_DLFrameLayout: dispatchTouchEvent: true
    12-05 15:38:03.242  V/DL_MainActivity: dispatchTouchEvent: true
    12-05 15:38:03.268  V/DL_MainActivity: dispatchTouchEvent: MOVE
    12-05 15:38:03.268  I/DL_DLFrameLayout: dispatchTouchEvent: MOVE
    12-05 15:38:03.268  I/DL_DLFrameLayout: onTouchEvent: MOVE
    12-05 15:38:03.269  I/DL_DLFrameLayout: onTouchEvent: true
    12-05 15:38:03.269  I/DL_DLFrameLayout: dispatchTouchEvent: true
    12-05 15:38:03.269  V/DL_MainActivity: dispatchTouchEvent: true
    12-05 15:38:03.285  V/DL_MainActivity: dispatchTouchEvent: MOVE
    12-05 15:38:03.285  I/DL_DLFrameLayout: dispatchTouchEvent: MOVE
    12-05 15:38:03.285  I/DL_DLFrameLayout: onTouchEvent: MOVE
    12-05 15:38:03.285  I/DL_DLFrameLayout: onTouchEvent: true
    12-05 15:38:03.285  I/DL_DLFrameLayout: dispatchTouchEvent: true
    12-05 15:38:03.285  V/DL_MainActivity: dispatchTouchEvent: true
    12-05 15:38:03.302  V/DL_MainActivity: dispatchTouchEvent: MOVE
    12-05 15:38:03.302  I/DL_DLFrameLayout: dispatchTouchEvent: MOVE
    12-05 15:38:03.302  I/DL_DLFrameLayout: onTouchEvent: MOVE
    12-05 15:38:03.302  I/DL_DLFrameLayout: onTouchEvent: true
    12-05 15:38:03.302  I/DL_DLFrameLayout: dispatchTouchEvent: true
    12-05 15:38:03.302  V/DL_MainActivity: dispatchTouchEvent: true
    12-05 15:38:03.318  V/DL_MainActivity: dispatchTouchEvent: MOVE
    12-05 15:38:03.318  I/DL_DLFrameLayout: dispatchTouchEvent: MOVE
    12-05 15:38:03.318  I/DL_DLFrameLayout: onTouchEvent: MOVE
    12-05 15:38:03.318  I/DL_DLFrameLayout: onTouchEvent: true
    12-05 15:38:03.318  I/DL_DLFrameLayout: dispatchTouchEvent: true
    12-05 15:38:03.318  V/DL_MainActivity: dispatchTouchEvent: true
    12-05 15:38:03.323  V/DL_MainActivity: dispatchTouchEvent: UP
    12-05 15:38:03.323  I/DL_DLFrameLayout: dispatchTouchEvent: UP
    12-05 15:38:03.323  I/DL_DLFrameLayout: onTouchEvent: UP
    12-05 15:38:03.323  I/DL_DLFrameLayout: onTouchEvent: true
    12-05 15:38:03.323  I/DL_DLFrameLayout: dispatchTouchEvent: true
    12-05 15:38:03.323  V/DL_MainActivity: dispatchTouchEvent: true
    //事件确实没有传递到子View中,ViewGroup接收了MOVE/UP事件

大家可以下载源码,察看其他情况下的输出结果


你可能感兴趣的:(TouchEvent,View,Android)