说明:本博客为原创,转载请注明出处 CSDN-ANDROID 笔记栈
由于作者水平有限,错误在所难免,请见谅,可以留言,本人会及时改正
索引
Android Touch事件主要有三个方法:
dispatchTouchEvent(分发): Touch事件的入口方法
onInterceptTouchEvent(拦截):ViewGroup拦截事件,不传递给子View
onTouchEvent(处理):是否消费事件
Activity和View都可以处理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被消费
}
传递关系图
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事件
大家可以下载源码,察看其他情况下的输出结果