事件之Touch 事件的分发和消费机制
Android 中与 Touch 事件相关的方法包括:dispatchTouchEvent(MotionEvent ev)、onInterceptTouchEvent(MotionEvent ev)、onTouchEvent(MotionEvent ev);能够响应这些方法的控件包括:ViewGroup、View、Activity。方法与控件的对应关系如下表所示:
| Touch 事件相关方法 | 方法功能 | ViewGroup | View | Activity |
| public boolean dispatchTouchEvent(MotionEvent ev) | 事件分发 | Yes | Yes | Yes |
| public boolean onInterceptTouchEvent(MotionEvent ev) | 事件拦截 | Yes | Yes | No |
| public boolean onTouchEvent(MotionEvent ev) | 事件响应 | Yes | Yes | Yes |
从这张表中我们可以看到 ViewGroup 和 View 对与 Touch 事件相关的三个方法均能响应,而 Activity 对 onInterceptTouchEvent(MotionEvent ev) 也就是事件拦截不进行响应。
另外需要注意的是 View 对 dispatchTouchEvent(MotionEvent ev) 和onInterceptTouchEvent(MotionEvent ev) 的响应的前提是可以向该 View 中添加子 View,如果当前的 View 已经是一个最小的单元 View(比如 TextView),那么就无法向这个最小 View 中添加子 View,也就无法向子 View 进行事件的分发和拦截,
所以它没有dispatchTouchEvent(MotionEvent ev) 和 onInterceptTouchEvent(MotionEvent ev),只有 onTouchEvent(MotionEvent ev)。
一、Touch 事件分析
▐ 事件分发:public boolean dispatchTouchEvent(MotionEvent ev)
Touch 事件发生时 Activity 的 dispatchTouchEvent(MotionEvent ev) 方法,会以隧道方式(从根元素依次往下传递直到最内层子元素或在中间某一元素中由于某一条件停止传递)将事件传递给最外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法,并由该 View的 dispatchTouchEvent(MotionEvent ev) 方法对事件进行分发。dispatchTouchEvent 的事件分发逻辑如下:
- 如果 return true,事件会分发给当前 View 并由 dispatchTouchEvent 方法进行消费,同时事件会停止向下传递;
- 如果 return false,事件分发分为两种情况:
- 如果当前 View 获取的事件直接来自 Activity,则会将事件返回给 Activity 的 onTouchEvent 进行消费;
- 如果当前 View 获取的事件来自外层父控件,则会将事件返回给父 View 的 onTouchEvent 进行消费。
- 如果返回系统默认的 super.dispatchTouchEvent(ev),事件会自动的分发给当前 View 的 onInterceptTouchEvent 方法。
▐ 事件拦截:public boolean onInterceptTouchEvent(MotionEvent ev)
在外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法返回系统默认的 super.dispatchTouchEvent(ev) 情况下,事件会自动的分发给当前 View 的 onInterceptTouchEvent 方法。onInterceptTouchEvent 的事件拦截逻辑如下:
- 如果 onInterceptTouchEvent 返回 true,则表示将事件进行拦截,并将拦截到的事件交由当前 View 的 onTouchEvent 进行处理;
- 如果 onInterceptTouchEvent 返回 super.onInterceptTouchEvent(ev),事件默认会被拦截,并将拦截到的事件交由当前 View 的 onTouchEvent 进行处理。
- 如果 onInterceptTouchEvent 返回 false,则表示将事件放行,当前 View 上的事件会被传递到子 View 上,再由子 View 的 dispatchTouchEvent 来开始这个事件的分发;
▐ 事件响应:public boolean onTouchEvent(MotionEvent ev)
在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 并且 onInterceptTouchEvent 返回 true 或返回 super.onInterceptTouchEvent(ev) 的情况下 onTouchEvent 会被调用。onTouchEvent 的事件响应逻辑如下:
- 如果事件传递到当前 View 的 onTouchEvent 方法,而该方法返回了 false,那么这个事件会从当前 View 向上传递,并且都是由上层 View 的 onTouchEvent 来接收,如果传递到上面的 onTouchEvent 也返回 false,这个事件就会“消失”,而且接收不到下一次事件。
- 如果返回了 true 则会接收并消费该事件。
- 如果返回 super.onTouchEvent(ev) 默认处理事件的逻辑和返回 false 时相同。
到这里,与 Touch 事件相关的三个方法就分析完毕了。下面的内容会通过各种不同的的测试案例来验证上文中三个方法对事件的处理逻辑。
二、Touch 案例介绍
同样在开始进行案例分析之前,我需要说明测试案例的结构,因为所有的测试都是针对这一个案例来进行的,测试中只是通过修改每个控件中与 Touch 事件相关的三个方法的返回值来体现不同的情况。先来看张图:

上面的图为测试案例的布局文件 UI 显示效果,布局文件代码如下:
<?xml version="1.0" encoding="utf-8"?>
<cn.sunzn.tevent.TouchEventFather xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#468AD7"
android:gravity="center"
android:orientation="vertical" > <cn.sunzn.tevent.TouchEventChilds
android:id="@+id/childs"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center"
android:background="#E1110D"
android:text="@string/hello" /> </cn.sunzn.tevent.TouchEventFather>
蓝色背景为一个自定义控件 TouchEventFather,该控件为外层 View,继承自 LinearLayout,实现代码如下:
package cn.sunzn.tevent; import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout; public class TouchEventFather extends LinearLayout { public TouchEventFather(Context context) {
super(context);
} public TouchEventFather(Context context, AttributeSet attrs) {
super(context, attrs);
} public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("sunzn", "TouchEventFather | dispatchTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
return super.dispatchTouchEvent(ev);
} public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.i("sunzn", "TouchEventFather | onInterceptTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
return super.onInterceptTouchEvent(ev);
} public boolean onTouchEvent(MotionEvent ev) {
Log.d("sunzn", "TouchEventFather | onTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
return super.onTouchEvent(ev);
} }
红色背景为一个自定义控件 TouchEventChilds,该控件为内层 View,为 TouchEventFather 的子 View,同样继承自 LinearLayout,实现代码如下:
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout; public class TouchEventChilds extends LinearLayout { public TouchEventChilds(Context context) {
super(context);
} public TouchEventChilds(Context context, AttributeSet attrs) {
super(context, attrs);
} public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("sunzn", "TouchEventChilds | dispatchTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
return super.dispatchTouchEvent(ev);
} public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.i("sunzn", "TouchEventChilds | onInterceptTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
return super.onInterceptTouchEvent(ev);
} public boolean onTouchEvent(MotionEvent ev) {
Log.d("sunzn", "TouchEventChilds | onTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
return super.onTouchEvent(ev);
} }
接着实现 Activity 的代码,因为控件所有的事件都是通过 Activity 的 dispatchTouchEvent 进行分发的;除此之外还需要重写 Activity 的 onTouchEvent 方法,这是因为如果一个控件直接从 Activity 获取到事件,这个事件会首先被传递到控件的 dispatchTouchEvent 方法,如果这个方法 return false,事件会以冒泡方式返回给 Activity 的 onTouchEvent 进行消费。实现代码如下:
package cn.sunzn.tevent; import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent; public class TouchEventActivity extends Activity { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
} public boolean dispatchTouchEvent(MotionEvent ev) {
Log.w("sunzn", "TouchEventActivity | dispatchTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
return super.dispatchTouchEvent(ev);
} public boolean onTouchEvent(MotionEvent event) {
Log.w("sunzn", "TouchEventActivity | onTouchEvent --> " + TouchEventUtil.getTouchAction(event.getAction()));
return super.onTouchEvent(event);
} }
最后再附上 TouchEventUtil 的代码,TouchEventUtil 中并没有做多少事情,只是将以上 2 个自定义控件中各个方法的 MotionEvent 集中到一个工具类中并将其对应的动作以 String 形式返回,这样处理更便于实时观察控件的事件。代码如下:
package cn.sunzn.tevent;
import android.view.MotionEvent;
public class TouchEventUtil {
public static String getTouchAction(int actionId) {
String actionName = "Unknow:id=" + actionId;
switch (actionId) {
case MotionEvent.ACTION_DOWN:
actionName = "ACTION_DOWN";
break;
case MotionEvent.ACTION_MOVE:
actionName = "ACTION_MOVE";
break;
case MotionEvent.ACTION_UP:
actionName = "ACTION_UP";
break;
case MotionEvent.ACTION_CANCEL:
actionName = "ACTION_CANCEL";
break;
case MotionEvent.ACTION_OUTSIDE:
actionName = "ACTION_OUTSIDE";
break;
}
return actionName;
}
}
三、Touch 案例分析
Case 1
| 拦截条件 | |||||||||
| 控件名称 | dispatchTouchEvent 返回值 | onInterceptTouchEvent 返回值 | onTouchEvent 返回值 | ||||||
| TouchEventActivity | super.dispatchTouchEvent(ev) | --- | super.onTouchEvent(ev) | ||||||
| TouchEventFather | false | super.onInterceptTouchEvent(ev) | super.onTouchEvent(ev) | ||||||
| TouchEventChilds | super.dispatchTouchEvent(ev) | super.onInterceptTouchEvent(ev) | super.onTouchEvent(ev) | ||||||
| 运行结果 | |||||||||
| Level | Time | PID | Application | Tag | Text | ||||
| W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_DOWN | ||||
| E | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_DOWN | ||||
| W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_DOWN | ||||
| W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_UP | ||||
| W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_UP | ||||
| 结果分析 | |||||||||
|
代码运行后,事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分发给 TouchEventFather 控件的dispatchTouchEvent,而该控件的 dispatchTouchEvent 返回 false,表示对获取到的事件停止向下传递,同时也不对该事件进行消费。 由于 TouchEventFather 获取的事件直接来自 TouchEventActivity ,则会将事件返回给 TouchEventActivity 的 onTouchEvent 进行消费,最后直接由 TouchEventActivity 来响应手指移动和抬起事件。 |
|||||||||
Case 2
| 拦截条件 | |||||||||
| 控件名称 | dispatchTouchEvent 返回值 | onInterceptTouchEvent 返回值 | onTouchEvent 返回值 | ||||||
| TouchEventActivity | super.dispatchTouchEvent(ev) | --- | super.onTouchEvent(ev) | ||||||
| TouchEventFather | true | super.onInterceptTouchEvent(ev) | super.onTouchEvent(ev) | ||||||
| TouchEventChilds | super.dispatchTouchEvent(ev) | super.onInterceptTouchEvent(ev) | super.onTouchEvent(ev) | ||||||
| 运行结果 | |||||||||
| Level | Time | PID | Application | Tag | Text | ||||
| W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_DOWN | ||||
| E | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_DOWN | ||||
| W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE | ||||
| E | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE | ||||
| E | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE | ||||
| E | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_UP | ||||
| E | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_UP | ||||
| 结果分析 | |||||||||
|
代码运行后,事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分发给 TouchEventFather 控件的 dispatchTouchEvent,而该控件的 dispatchTouchEvent 返回 true,表示分发事件到 TouchEventFather 控件并由该控件的 dispatchTouchEvent 进行消费; TouchEventActivity 不断的分发事件到 TouchEventFather 控件的dispatchTouchEvent,而 TouchEventFather 控件的 dispatchTouchEvent 也不断的将获取到的事件进行消费。 |
|||||||||
Case 3
| 拦截条件 | |||||||||
| 控件名称 | dispatchTouchEvent 返回值 | onInterceptTouchEvent 返回值 | onTouchEvent 返回值 | ||||||
| TouchEventActivity | super.dispatchTouchEvent(ev) | --- | super.onTouchEvent(ev) | ||||||
| TouchEventFather | super.dispatchTouchEvent(ev) | true | super.onTouchEvent(ev) | ||||||
| TouchEventChilds | super.dispatchTouchEvent(ev) | super.onInterceptTouchEvent(ev) | super.onTouchEvent(ev) | ||||||
| 运行结果 | |||||||||
| Level | Time | PID | Application | Tag | Text | ||||
| W | 05-10 05:34:46.333 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_DOWN | ||||
| E | 05-10 05:34:46.333 | 481 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_DOWN | ||||
| I | 05-10 05:34:46.333 | 481 | cn.sunzn.tevent | sunzn | TouchEventFather | onInterceptTouchEvent --> ACTION_DOWN | ||||
| D | 05-10 05:34:46.333 | 481 | cn.sunzn.tevent | sunzn | TouchEventFather | onTouchEvent --> ACTION_DOWN | ||||
| W | 05-10 05:34:46.333 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_DOWN | ||||
| W | 05-10 05:34:46.343 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 05:34:46.343 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 05:34:46.423 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 05:34:46.423 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 05:34:46.433 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 05:34:46.433 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 05:34:46.442 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_UP | ||||
| W | 05-10 05:34:46.442 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_UP | ||||
| 结果分析 | |||||||||
|
代码运行后,事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分发给 TouchEventFather 控件的 dispatchTouchEvent, 而该控件的 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev),表示对事件进行分发并向下传递给 TouchEventFather 控件的 onInterceptTouchEvent 方法, 该方法返回 true 表示对所获取到的事件进行拦截并将事件传递给 TouchEventFather 控件的 onTouchEvent 进行处理,TouchEventFather 控件的 onTouchEvent 返回 super.onTouchEvent(ev) 表示对事件没有做任何处理直接将事件返回给上级控件, 由于 TouchEventFather 获取的事件直接来自 TouchEventActivity,所以 TouchEventFather 控件的 onTouchEvent 会将事件以冒泡方式直接返回给 TouchEventActivity 的 onTouchEvent 进行消费,后续的事件则会跳过 TouchEventFather 直接由 TouchEventActivity 的 onTouchEvent 消费来自 TouchEventActivity 自身分发的事件。 |
|||||||||
Case 4
| 拦截条件 | |||||||||
| 控件名称 | dispatchTouchEvent 返回值 | onInterceptTouchEvent 返回值 | onTouchEvent 返回值 | ||||||
| TouchEventActivity | super.dispatchTouchEvent(ev) | --- | super.onTouchEvent(ev) | ||||||
| TouchEventFather | super.dispatchTouchEvent(ev) | false | super.onTouchEvent(ev) | ||||||
| TouchEventChilds | super.dispatchTouchEvent(ev) | super.onInterceptTouchEvent(ev) | super.onTouchEvent(ev) | ||||||
| 运行结果 | |||||||||
| Level | Time | PID | Application | Tag | Text | ||||
| W | 05-10 06:31:47.565 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_DOWN | ||||
| E | 05-10 06:31:47.565 | 512 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_DOWN | ||||
| I | 05-10 06:31:47.565 | 512 | cn.sunzn.tevent | sunzn | TouchEventFather | onInterceptTouchEvent --> ACTION_DOWN | ||||
| E | 05-10 06:31:47.565 | 512 | cn.sunzn.tevent | sunzn | TouchEventChilds | dispatchTouchEvent --> ACTION_DOWN | ||||
| I | 05-10 06:31:47.565 | 512 | cn.sunzn.tevent | sunzn | TouchEventChilds | onInterceptTouchEvent --> ACTION_DOWN | ||||
| D | 05-10 06:31:47.565 | 512 | cn.sunzn.tevent | sunzn | TouchEventChilds | onTouchEvent --> ACTION_DOWN | ||||
| D | 05-10 06:31:47.565 | 512 | cn.sunzn.tevent | sunzn | TouchEventFather | onTouchEvent --> ACTION_DOWN | ||||
| W | 05-10 06:31:47.565 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_DOWN | ||||
| W | 05-10 06:31:47.652 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 06:31:47.652 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 06:31:47.732 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 06:31:47.732 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 06:31:47.812 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 06:31:47.812 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 06:31:47.892 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_UP | ||||
| W | 05-10 06:31:47.892 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_UP | ||||
| 结果分析 | |||||||||
|
代码运行后,事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分发给 TouchEventFather 控件的 dispatchTouchEvent,而该控件的 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev),表示对事件进行分发并向下传递给 TouchEventFather 控件的 onInterceptTouchEvent 方法, 该方法返回 false 表示事件会被放行并传递到子控件 TouchEventChilds 的 dispatchTouchEvent 方法,同样 TouchEventChilds 的 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev),表示对事件进行分发并向下传递给 TouchEventChilds 控件的 onInterceptTouchEvent 方法,TouchEventChilds 的 onInterceptTouchEvent 方法返回 super.onInterceptTouchEvent(ev) 默认会将事件传递给 TouchEventChilds 的 onTouchEvent 进行处理,TouchEventChilds 的 onTouchEvent 返回 super.onTouchEvent(ev) 表示对事件没有做任何处理直接将事件返回给上级控件,由于 TouchEventChilds 获取的事件直接来自 TouchEventFather,所以 TouchEventChilds 控件的 onTouchEvent 会将事件以冒泡方式直接返回给 TouchEventFather 的 onTouchEvent 进行消费,而 TouchEventFather 的 onTouchEvent 也返回了 super.onTouchEvent(ev),同样 TouchEventFather 的 onTouchEvent 也会将事件返回给上级控件,而 TouchEventFather 获取的事件直接来自 TouchEventActivity,所以 TouchEventFather 控件的 onTouchEvent 会将事件以冒泡方式直接返回给 TouchEventActivity 的 onTouchEvent 进行消费,后续的事件则会跳过 TouchEventFather 和 TouchEventChilds 直接由 TouchEventActivity 的 onTouchEvent 消费来自 TouchEventActivity 自身分发的事件。 |
|||||||||
Case 5
| 拦截条件 | |||||||||
| 控件名称 | dispatchTouchEvent 返回值 | onInterceptTouchEvent 返回值 | onTouchEvent 返回值 | ||||||
| TouchEventActivity | super.dispatchTouchEvent(ev) | --- | super.onTouchEvent(ev) | ||||||
| TouchEventFather | super.dispatchTouchEvent(ev) | false | super.onTouchEvent(ev) | ||||||
| TouchEventChilds | true | super.onInterceptTouchEvent(ev) | super.onTouchEvent(ev) | ||||||
| 运行结果 | |||||||||
| Level | Time | PID | Application | Tag | Text | ||||
| W | 05-10 08:11:18.403 | 574 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_DOWN | ||||
| E | 05-10 08:11:18.403 | 574 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_DOWN | ||||
| I | 05-10 08:11:18.403 | 574 | cn.sunzn.tevent | sunzn | TouchEventFather | onInterceptTouchEvent --> ACTION_DOWN | ||||
| E | 05-10 08:11:18.403 | 574 | cn.sunzn.tevent | sunzn | TouchEventChilds | dispatchTouchEvent --> ACTION_DOWN | ||||
| W | 05-10 08:11:19.652 | 574 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE | ||||
| E | 05-10 08:11:19.652 | 574 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_MOVE | ||||
| I | 05-10 08:11:19.652 | 574 | cn.sunzn.tevent | sunzn | TouchEventFather | onInterceptTouchEvent --> ACTION_MOVE | ||||
| E | 05-10 08:11:19.652 | 574 | cn.sunzn.tevent | sunzn | TouchEventChilds | dispatchTouchEvent --> ACTION_MOVE | ||||
| W | 05-10 08:11:19.872 | 574 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_UP | ||||
| E | 05-10 08:11:19.872 | 574 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_UP | ||||
| I | 05-10 08:11:19.872 | 574 | cn.sunzn.tevent | sunzn | TouchEventFather | onInterceptTouchEvent --> ACTION_UP | ||||
| E | 05-10 08:11:19.872 | 574 | cn.sunzn.tevent | sunzn | TouchEventChilds | dispatchTouchEvent --> ACTION_UP | ||||
| 结果分析 | |||||||||
| 代码运行后,事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分发给 TouchEventFather 控件的 dispatchTouchEvent,该控件的 dispatchTouchEvent 返回super.dispatchTouchEvent(ev),事件会分发到 TouchEventFather 的 onInterceptTouchEvent,onInterceptTouchEvent 返回 false 表示放行当先事件;事件会被传递到子控件 TouchEventChilds 的 dispatchTouchEvent 方法,dispatchTouchEvent 返回 true 表示事件被分发到 TouchEventChilds 控件并由该控件的 dispatchTouchEvent 方法消费。后续的事件也会不断的重复上面的逻辑最终被 TouchEventChilds 的 dispatchTouchEvent 消费。 | |||||||||
事件之Touch 事件的分发和消费机制的更多相关文章
- 通俗理解Android事件分发与消费机制
深入:Android Touch事件传递机制全面解析(从WMS到View树) 通俗理解Android事件分发与消费机制 说起Android滑动冲突,是个很常见的场景,比如SliddingMenu与Li ...
- 手持设备点击响应速度,鼠标事件与touch事件的那些事
前言 现在一直在做移动端的开发,这次将单页应用的网页内嵌入了app,于是老大反映了一个问题:app应用点击响应慢!我开始不以为然,于是拿着网页版的试了试,好像确实有一定延迟,于是开始了研究,最后选择了 ...
- Android事件分发机制(一) Touch 事件的分发和消费机制
Android 中与 Touch 事件相关的方法包括:dispatchTouchEvent(MotionEvent ev).onInterceptTouchEvent(MotionEvent ev). ...
- Android 编程下 Touch 事件的分发和消费机制
Android 中与 Touch 事件相关的方法包括:dispatchTouchEvent(MotionEvent ev).onInterceptTouchEvent(MotionEvent ev). ...
- Touch 事件的分发和消费机制
Android 中与 Touch 事件相关的方法包括:dispatchTouchEvent(MotionEvent ev).onInterceptTouchEvent(MotionEvent ev). ...
- Android 编程下Touch 事件的分发和消费机制
1.事件分发:public boolean dispatchTouchEvent(MotionEvent ev) Touch 事件发生时 Activity 的 dispatchTouchEvent(M ...
- touch事件的分发和消费机制
Android 中与 Touch 事件相关的方法包括:dispatchTouchEvent(MotionEvent ev).onInterceptTouchEvent(MotionEvent ev). ...
- Android 编程下Touch 事件的分发和消费机制和OnTouchListener,OnClickListener和OnLongClickListener的关系
1.事件分发:public boolean dispatchTouchEvent(MotionEvent ev) Touch 事件发生时 Activity 的 dispatchTouchEvent(M ...
- Android事件分发和消费机制(转载)
原文链接:http://www.cnblogs.com/sunzn/archive/2013/05/10/3064129.html Android 中与 Touch 事件相关的方法包括:dispatc ...
随机推荐
- SVN三种合并类型
https://blog.csdn.net/zht666/article/details/36178117 转自:http://wenku.baidu.com/link?url=pnALYESJnX0 ...
- gaia 开源多语言的pipeline 平台
gaia 是一个支持goalng.java.c++.python,nodejs (还在开发中)的pipeline 平台,我们可以方便的进行pipeline构建的 添加,同时也可以做为sdk 在我们的项 ...
- NPOI之Excel——设置单元格背景色
NPOI Excel 单元格颜色对照表,在引用了 NPOI.dll 后可通过 ICellStyle 接口的 FillForegroundColor 属性实现 Excel 单元格的背景色设置,FillP ...
- 漫谈 C++ 虚函数 的 实现原理
文中讲述的原理是推理和探讨 , 和现实中的实现不一定完全相同 . C++ 的 虚函数 , 编译器 会 生成一个 虚函数表 . 虚函数表, 实际上是 编译器 在 内存 中 划定 的 一块 区域, 用于存 ...
- 混合pyqt和qtcreator
目的:测试能否用qtcreator编辑ui资源,而用python编写代码逻辑 import sysfrom PyQt4 import QtGui, uic class MyWindow(QtGui.Q ...
- jdk动态代理在idea的debug模式下不断刷新tostring方法
在jdk的动态代理下,在使用idea进入动态代理的debug模式下,单步调试会刷新idea的tostring方法,让他自己重走了一遍代理 这个问题暂时无解
- sql语句实战
1,排名,自身连接,用count,去重用distinct 2,累加,和上面一样,自身连接,用sum 3,count函数不用group by只有一组
- 在外网访问家里面的电脑 和 DMZ
方法1:使用 MDZ ( demilitarized zone), 中文意思 非武装的区域.我们的家用电脑一般都在 路由器所在的 C类内网(192.X.X.X 的 ip).外网是不能直接访问内网的. ...
- 相似度与距离计算python代码实现
#定义几种距离计算函数 #更高效的方式为把得分向量化之后使用scipy中定义的distance方法 from math import sqrt def euclidean_dis(rating1, r ...
- Jenkins进阶-邮件通知(9)
公司内部每天大概会发布N多版本,也不能派员工一直去盯着版本发布,所以希望发布完成后通知相关人员,Jenkins最早采用通知机制就是短信和邮件,由于短信成本很高,所以我们一般在发布结束后会采用邮件.现在 ...