在自定义 View 中,常常须要处理 Android 事件分发的问题,尤为在有多个输入设备(如遥控、鼠标、游戏手柄等)时,事件处理问题尤其突出。Android 事件分发机制,一直以来都是一个让众多开发者困扰的难点,至少笔者在工做的前几年中,没有特地研究它以前,就常常云里雾里。
View 的事件分发机制实际上就是一个很是经典的责任链模式。
Android 责任链设计模式学习应用实例android
在讲 Android 事件分发机制前,先简单了解一些 MotionEvent,由于它就是这个“事件”。如下截取了部分源码中的描述:设计模式
...... * <p> * Motion events describe movements in terms of an action code and a set of axis values. * The action code specifies the state change that occurred such as a pointer going * down or up. The axis values describe the position and other movement properties. * </p> ...... public final class MotionEvent extends InputEvent implements Parcelable { public static final int ACTION_DOWN = 0; public static final int ACTION_UP = 1; public static final int ACTION_MOVE = 2; ...... }
MotionEvent,顾名思义,动做事件的意思。它经过一个 action 码和一套坐标值来描述动做。action 码指定了当如指针按下或者抬起等事件发生时的状态改变,坐标值则描述了事件在屏幕中的位置和其它动做属性值。
平时触摸屏幕时,一个最简单的事件包括了“ACTION_DOWN”和“ACTION_UP”,“ACTION_DOWN”表示手指按下,而““ACTION_UP”表示手指抬起来,这两个 action 才构成了一个完整的事件。若是手指在屏幕上有移动,还会包含“ACTION_MOVE”,此时一个完整的事件就包括“ACTION_DOWN”,多个“ACTION_MOVE”,“ACTION_UP”。固然,实际工做中会有不少复杂的状况出现,可能会出现一些其它的 aciton,本文为了演示的方便,只考虑“ACTION_DOWN”和“ACTION_UP”的场景。ide
为了演示事件分发机制的工做流程,这里编写一个示例来进行演示。整个 Acitivity 模拟 Boss 角色;在其界面中的最外层模拟 PM,继承自 RelativeLayout,是一个父布局;PM 下嵌套一层,也是一个父布局,继承自 RelativeLayout,用于模拟 Team Leader;最里面一层是一个叶子 View,继承自 Button,模拟 Programmer。效果图及对应代码分别以下。函数
以下的代码中,须要重写的方法 dispatchTouchEvent(MotionEvent ev)、onInterceptTouchEvent(MotionEvent ev)、onTouchEvent(MotionEvent ev)均返回默认值,即 super.xxx。平时我们使用系统原生控件时,没法修改它们的源码,因此系统给的默认场景就是这样的。
(1)Boss:EventDemoActivity布局
public class EventDemoActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_event_demo); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i("songzheweiwang","[EventDemoActivity-->dispatchTouchEvent]ev="+EventUtil.parseAction(ev.getAction())); return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.i("songzheweiwang","[EventDemoActivity-->onTouchEvent]event="+EventUtil.parseAction(event.getAction())); return super.onTouchEvent(event); } }
(2)PM:ViewGroupOuter学习
public class ViewGroupOuter extends RelativeLayout { public ViewGroupOuter(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i("songzheweiwang","[ViewGroupOuter-->dispatchTouchEvent]ev="+EventUtil.parseAction(ev.getAction())); return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.i("songzheweiwang","[ViewGroupOuter-->onInterceptTouchEvent]ev="+EventUtil.parseAction(ev.getAction())); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.i("songzheweiwang","[ViewGroupOuter-->onTouchEvent]event="+EventUtil.parseAction(event.getAction())); return super.onTouchEvent(event); } }
(3)Team Leader:ViewGroupMiddlespa
public class ViewGroupMiddle extends RelativeLayout { public ViewGroupMiddle(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i("songzheweiwang","[ViewGroupMiddle-->dispatchTouchEvent]ev="+EventUtil.parseAction(ev.getAction())); return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.i("songzheweiwang","[ViewGroupMiddle-->onInterceptTouchEvent]ev="+EventUtil.parseAction(ev.getAction())); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.i("songzheweiwang","[ViewGroupMiddle-->onTouchEvent]event="+EventUtil.parseAction(event.getAction())); return super.onTouchEvent(event); } }
(4)Programmer:ViewInner
这里先以 Button 为例,由于 Button 默认是能够处理 Touch 事件的,也就是说,事件传到这里时,能被完美地处理掉。设计
@SuppressLint("AppCompatCustomView") public class ViewInner extends Button{ public ViewInner(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.i("songzheweiwang","[ViewInner-->dispatchTouchEvent]event="+EventUtil.parseAction(event.getAction())); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.i("songzheweiwang","[ViewInner-->onTouchEvent]event="+EventUtil.parseAction(event.getAction())); return super.onTouchEvent(event); } }
(5)辅助类:3d
public class EventUtil { public static String parseAction(int action) { String actionName = "Unknow:action=" + action; switch (action) { case MotionEvent.ACTION_DOWN: actionName = "ACTION_DOWN"; break; case MotionEvent.ACTION_MOVE: actionName = "ACTION_MOVE"; break; case MotionEvent.ACTION_UP: actionName = "ACTION_UP"; break; default: break; } return actionName; } }
点击上图中不一样的区域,会有不一样的结果。这里点击最中间的 View,点击其余区域的结果及分析,咱们在后面再介绍。指针
06-07 13:35:23.483 18298-18298/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 13:35:23.483 18298-18298/com.example.demos I/songzheweiwang: [ViewGroupOuter-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 13:35:23.483 18298-18298/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onInterceptTouchEvent]ev=ACTION_DOWN 06-07 13:35:23.483 18298-18298/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 13:35:23.483 18298-18298/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->onInterceptTouchEvent]ev=ACTION_DOWN 06-07 13:35:23.483 18298-18298/com.example.demos I/songzheweiwang: [ViewInner-->dispatchTouchEvent]event=ACTION_DOWN 06-07 13:35:23.483 18298-18298/com.example.demos I/songzheweiwang: [ViewInner-->onTouchEvent]event=ACTION_DOWN 06-07 13:35:23.524 18298-18298/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_UP 06-07 13:35:23.525 18298-18298/com.example.demos I/songzheweiwang: [ViewGroupOuter-->dispatchTouchEvent]ev=ACTION_UP 06-07 13:35:23.525 18298-18298/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onInterceptTouchEvent]ev=ACTION_UP 06-07 13:35:23.525 18298-18298/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->dispatchTouchEvent]ev=ACTION_UP 06-07 13:35:23.525 18298-18298/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->onInterceptTouchEvent]ev=ACTION_UP 06-07 13:35:23.525 18298-18298/com.example.demos I/songzheweiwang: [ViewInner-->dispatchTouchEvent]event=ACTION_UP 06-07 13:35:23.525 18298-18298/com.example.demos I/songzheweiwang: [ViewInner-->onTouchEvent]event=ACTION_UP
该事件包含了两 action:ACTION_DOWN 和 ACTION_UP。前咱们说过,Programmer 完美处理好了事件,本次流程就到这里为止了,再也不传递,Boss 认为团队有能力处理这类任务,因此相似的任务也会一样会交给手下的团队,因此 ACTION_UP 也走了相似的流程,那么整个事件就算完成了,由 Programmer 完美完成。整个事件的序列图以下所示:
前面一直提到 Touch 事件的 3 个主要方法:dispatchTouchEvent(MotionEvent ev)、onInterceptTouchEvent(MotionEvent ev)和 onTouchEvent(MotionEvent ev),那么这三个方法的功能到底是什么呢?这里能够看看下面的表格的总结:
其实咱们能够从函数名称来大体判断其功能,dispatchTouchEvent,分发触摸事件,就是把事件传递下去,准确来讲就是是否要传递到子 View 以及本身的 onInterceptTouchEvent 方法和 onTouchEvent 方法,也就是说,不只管子 View,还管自身剩下的两个回调方法。onInterceptTouchEvent,事件拦截,它只管自身子 View,而不会影响到自身后面两个方法的执行,若是拦截了,能够记忆为让本身的手下们无事可作。这两个方法容易混淆,须要重点理解和记忆。
在上述表格中还能够看到,Activity 是没法回调 onIntercepTouchEvent 方法的,由于这个方法是 ViewGroup 中的方法,而 Activity 也不是 View 体系中,不是视图类,因此没有这个方法。咱们能够这样记忆,Activity 是 Boss,不是打工行列中的一员,本身的任务就是让下面的打工者没去作事情,全部该方法对他来讲,没有意义。叶子 View 也没有这个方法,由于本身没有子 View 了,也没有拦截的意义。
因为这三个方法都是 boolean 值,再加上默认情形下会返回 super.xxx,这样,每个方法都会有三种可选值。我们这里先了解一下每一种取值会产生怎么样的结果。
Touch 事件发生时,Activity 的 dispatchTouchEvent 方法会将事件传递给最外层控件的 dispatchTouchEvent 方法,并由该控件进行分发下去。从根元素依次往下传递,一直到最里面的叶子 View,或者中途被某个控件终止,才结束这个派发过程。其分发逻辑以下:
在当前控件的 dispatchTouchEvent 方法返回默认的方式时,其拦截逻辑以下:
上一节中介绍了 Touch 的 3 个主要方法的返回值下,对事件分发的处理逻辑。本节中,我们经过修改前面这三个方法中的返回值,来验证事件的分发流程(注意:如下状况下均点击中间的 ViewInner 控件)。
1 06-07 19:15:53.220 25298-25298/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_DOWN 2 06-07 19:15:53.221 25298-25298/com.example.demos I/songzheweiwang: [ViewGroupOuter-->dispatchTouchEvent]ev=ACTION_DOWN 3 06-07 19:15:53.221 25298-25298/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onInterceptTouchEvent]ev=ACTION_DOWN 4 06-07 19:15:53.222 25298-25298/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->dispatchTouchEvent]ev=ACTION_DOWN5 06-07 19:15:53.237 25298-25298/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_UP 6 06-07 19:15:53.237 25298-25298/com.example.demos I/songzheweiwang: [ViewGroupOuter-->dispatchTouchEvent]ev=ACTION_UP 7 06-07 19:15:53.237 25298-25298/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onInterceptTouchEvent]ev=ACTION_UP 8 06-07 19:15:53.238 25298-25298/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->dispatchTouchEvent]ev=ACTION_UP
参照第四节中的结论,ViewGroupMiddle 的 dispatchTouchEvent 返回 true,事件从 Acitivty,通过 ViewGroupOuter 分发到 ViewGroupMiddle 中,在其 dispatchTouchEvent 方法中处理。ViewGroupMiddle 的 onInterceptTouchEvent 和 onTouchEvent 均不会被调用,且事件也不会再往 ViewInner 中传递。既然事件是在 ViewGroupMiddle 的 dispatchTouchEvent 中被处理了,在 Boss EventDemoActivity 看来,本身手下的团队有能力处理这类事件,因此 ACTION_UP 也被派发下来,走一样的流程,直到全部事件处理完毕。
06-07 19:31:50.093 25668-25668/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 19:31:50.094 25668-25668/com.example.demos I/songzheweiwang: [ViewGroupOuter-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 19:31:50.094 25668-25668/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onInterceptTouchEvent]ev=ACTION_DOWN 06-07 19:31:50.094 25668-25668/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 19:31:50.094 25668-25668/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onTouchEvent]event=ACTION_DOWN 06-07 19:31:50.094 25668-25668/com.example.demos I/songzheweiwang: [EventDemoActivity-->onTouchEvent]event=ACTION_DOWN 06-07 19:31:50.151 25668-25668/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_UP 06-07 19:31:50.151 25668-25668/com.example.demos I/songzheweiwang: [EventDemoActivity-->onTouchEvent]event=ACTION_UP
参照第四节中的结论,ViewGroupMiddle 的 dispatchTouchEvent 返回 true,事件从 Acitivty,通过 ViewGroupOuter 分发到 ViewGroupMiddle 中,且在 dispatchTouchEvent 方法中不处理此事件。ViewGroupMiddle 的 onInterceptTouchEvent 和 onTouchEvent 均不会被调用,且事件也不会再往 ViewInner 中传递。本身处理不了事件,传递给上一级的 onTouchEvent 来处理,上一级也没能力处理,最后传给了 EventDemoActivity 的 onTouchEvent。此时,在 Boss 看来,本身手下团队处理不了这类事件,因此后面的事件就再也不传递下去,都有本身来处理。
06-07 19:41:08.894 26055-26055/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 19:41:08.894 26055-26055/com.example.demos I/songzheweiwang: [ViewGroupOuter-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 19:41:08.894 26055-26055/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onInterceptTouchEvent]ev=ACTION_DOWN 06-07 19:41:08.894 26055-26055/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 19:41:08.894 26055-26055/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->onInterceptTouchEvent]ev=ACTION_DOWN 06-07 19:41:08.894 26055-26055/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->onTouchEvent]event=ACTION_DOWN 06-07 19:41:08.894 26055-26055/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onTouchEvent]event=ACTION_DOWN 06-07 19:41:08.895 26055-26055/com.example.demos I/songzheweiwang: [EventDemoActivity-->onTouchEvent]event=ACTION_DOWN 06-07 19:41:08.900 26055-26055/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_UP 06-07 19:41:08.901 26055-26055/com.example.demos I/songzheweiwang: [EventDemoActivity-->onTouchEvent]event=ACTION_UP
事件在 ViewGroupMiddle 中被拦截了,事件再也不派发到 ViewInner 中,而是交给本身的 onTouchEvent 来处理。前面说过,ViewGroupMiddle 继承自 RelativeLayout,默认是没有能力处理 Touch 事件的,因而就传递到上一级的 onTouchEvent 中,直到 EventDemoActivity 中的 onTouchEvent 方法。此时,在 Boss 看来,本身手下团队处理不了这类事件,因此后面的事件就再也不传递下去,都有本身来处理。
06-07 19:48:58.130 26400-26400/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 19:48:58.130 26400-26400/com.example.demos I/songzheweiwang: [ViewGroupOuter-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 19:48:58.130 26400-26400/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onInterceptTouchEvent]ev=ACTION_DOWN 06-07 19:48:58.130 26400-26400/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 19:48:58.130 26400-26400/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->onInterceptTouchEvent]ev=ACTION_DOWN 06-07 19:48:58.130 26400-26400/com.example.demos I/songzheweiwang: [ViewInner-->dispatchTouchEvent]event=ACTION_DOWN 06-07 19:48:58.131 26400-26400/com.example.demos I/songzheweiwang: [ViewInner-->onTouchEvent]event=ACTION_DOWN 06-07 19:48:58.131 26400-26400/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->onTouchEvent]event=ACTION_DOWN 06-07 19:48:58.131 26400-26400/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onTouchEvent]event=ACTION_DOWN 06-07 19:48:58.131 26400-26400/com.example.demos I/songzheweiwang: [EventDemoActivity-->onTouchEvent]event=ACTION_DOWN 06-07 19:48:58.162 26400-26400/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_UP 06-07 19:48:58.162 26400-26400/com.example.demos I/songzheweiwang: [EventDemoActivity-->onTouchEvent]event=ACTION_UP
这种状况下,和使用默认 super.onInterceptTouchEvent 时是同样的,Log 中中的日志也验证了这一点。事件派发流程在第三节中详细讲解过,这里就再也不赘述了。
06-07 19:53:51.516 26711-26711/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 19:53:51.517 26711-26711/com.example.demos I/songzheweiwang: [ViewGroupOuter-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 19:53:51.517 26711-26711/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onInterceptTouchEvent]ev=ACTION_DOWN 06-07 19:53:51.517 26711-26711/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 19:53:51.517 26711-26711/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->onInterceptTouchEvent]ev=ACTION_DOWN 06-07 19:53:51.517 26711-26711/com.example.demos I/songzheweiwang: [ViewInner-->dispatchTouchEvent]event=ACTION_DOWN 06-07 19:53:51.517 26711-26711/com.example.demos I/songzheweiwang: [ViewInner-->onTouchEvent]event=ACTION_DOWN 06-07 19:53:51.517 26711-26711/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->onTouchEvent]event=ACTION_DOWN 06-07 19:53:51.582 26711-26711/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_UP 06-07 19:53:51.583 26711-26711/com.example.demos I/songzheweiwang: [ViewGroupOuter-->dispatchTouchEvent]ev=ACTION_UP 06-07 19:53:51.583 26711-26711/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onInterceptTouchEvent]ev=ACTION_UP 06-07 19:53:51.583 26711-26711/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->dispatchTouchEvent]ev=ACTION_UP 06-07 19:53:51.583 26711-26711/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->onTouchEvent]event=ACTION_UP
事件依次传递到 ViewInner 的 onTouchEvent 方法中,ViewInner 默认没有能力处理该事件,传递到上一级 ViewGroupMiddle 中的 onTouchEvent 来处理。返回 true 表示被处理了,本次事件在此停止了。在 Boss 看来,手下团队有能力处理这类事件,因此后面的 ACTION_UP 事件仍然往下分发了。这里须要注意的是,ACTION_UP 在 ViewGroupMiddle 的 dispatchTouchEvent 执行后直接进入到其 onTouchEvent 方法中了,没有通过 onInterceptTouchEvent 方法走,也没有往 ViewInner 中分发。这个场景就好像,经过 ACTION_DOWN,ViewGroupMiddle 已经知道本身的手下 ViewInner 处理不了这类任务,因此当同类任务从上面领导发放到本身这里的时候,就不用再继续往下分发,而是直接直接就处理掉了。
06-07 20:09:49.746 27357-27357/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 20:09:49.746 27357-27357/com.example.demos I/songzheweiwang: [ViewGroupOuter-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 20:09:49.746 27357-27357/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onInterceptTouchEvent]ev=ACTION_DOWN 06-07 20:09:49.746 27357-27357/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 20:09:49.746 27357-27357/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->onInterceptTouchEvent]ev=ACTION_DOWN 06-07 20:09:49.746 27357-27357/com.example.demos I/songzheweiwang: [ViewInner-->dispatchTouchEvent]event=ACTION_DOWN 06-07 20:09:49.746 27357-27357/com.example.demos I/songzheweiwang: [ViewInner-->onTouchEvent]event=ACTION_DOWN 06-07 20:09:49.746 27357-27357/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->onTouchEvent]event=ACTION_DOWN 06-07 20:09:49.747 27357-27357/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onTouchEvent]event=ACTION_DOWN 06-07 20:09:49.747 27357-27357/com.example.demos I/songzheweiwang: [EventDemoActivity-->onTouchEvent]event=ACTION_DOWN 06-07 20:09:49.803 27357-27357/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_UP 06-07 20:09:49.803 27357-27357/com.example.demos I/songzheweiwang: [EventDemoActivity-->onTouchEvent]event=ACTION_UP
这里在 activity_event_demo.xml 中使用 ViewGroupMiddle 时添加[android:clickable="true"],将 ViewGroupMiddle 设置为默承认以处理 Touch 事件。当设置为 false 值时,从日志来看,代表 ViewGroupMiddle 不管是否有能力,都确实没有处理事件,而是传给了上级。
当 ViewGroupMiddle 中 onTouchEvent 返回默认的 super.onTouchEvent 时,咱们在第三节中分析过 ViewInner 有能处理和没有能力处理两种状况下的事件处理逻辑,这里笔者再也不赘述。如今还有一个结论须要读者验证,就是都在返回默认 super.xxx 状况下,能够在 ViewGroupMiddle 中 onTouchEvent 方法中打印出 super.onTouchEvent 的值。能够发现,若是 ViewGroupMiddle 中 onTouchEvent 方法能够处理事件,则值为 true,若是没有处理 Touch 事件的能力,则会返回 false。这一点在第四节中讲过。
在前面分析打印 log 结果的时候,笔者都着重强调了要点击正中心的 ViewInner。这是由于点击不一样的区域,会产生不一样的逻辑处理结果。那么点击区域和事件分发结果有什么样的关系呢?下面将第三节中的例子,3 个主要方法都返回默认的 super.xxx 方法,由外到内依次点击 Boss、PM、Team Leader、Programmer 四个区域。获得了以下的 log 信息:
06-07 20:27:44.390 28523-28523/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 20:27:44.391 28523-28523/com.example.demos I/songzheweiwang: [EventDemoActivity-->onTouchEvent]event=ACTION_DOWN 06-07 20:27:44.405 28523-28523/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_UP 06-07 20:27:44.405 28523-28523/com.example.demos I/songzheweiwang: [EventDemoActivity-->onTouchEvent]event=ACTION_UP 06-07 20:27:48.298 28523-28523/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 20:27:48.299 28523-28523/com.example.demos I/songzheweiwang: [ViewGroupOuter-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 20:27:48.299 28523-28523/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onInterceptTouchEvent]ev=ACTION_DOWN 06-07 20:27:48.299 28523-28523/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onTouchEvent]event=ACTION_DOWN 06-07 20:27:48.299 28523-28523/com.example.demos I/songzheweiwang: [EventDemoActivity-->onTouchEvent]event=ACTION_DOWN 06-07 20:27:48.338 28523-28523/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_UP 06-07 20:27:48.339 28523-28523/com.example.demos I/songzheweiwang: [EventDemoActivity-->onTouchEvent]event=ACTION_UP 06-07 20:27:52.681 28523-28523/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 20:27:52.681 28523-28523/com.example.demos I/songzheweiwang: [ViewGroupOuter-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 20:27:52.681 28523-28523/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onInterceptTouchEvent]ev=ACTION_DOWN 06-07 20:27:52.681 28523-28523/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 20:27:52.681 28523-28523/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->onInterceptTouchEvent]ev=ACTION_DOWN 06-07 20:27:52.682 28523-28523/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->onTouchEvent]event=ACTION_DOWN 06-07 20:27:52.682 28523-28523/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onTouchEvent]event=ACTION_DOWN 06-07 20:27:52.682 28523-28523/com.example.demos I/songzheweiwang: [EventDemoActivity-->onTouchEvent]event=ACTION_DOWN 06-07 20:27:52.749 28523-28523/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_UP 06-07 20:27:52.749 28523-28523/com.example.demos I/songzheweiwang: [EventDemoActivity-->onTouchEvent]event=ACTION_UP 06-07 20:27:57.448 28523-28523/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 20:27:57.449 28523-28523/com.example.demos I/songzheweiwang: [ViewGroupOuter-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 20:27:57.449 28523-28523/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onInterceptTouchEvent]ev=ACTION_DOWN 06-07 20:27:57.449 28523-28523/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->dispatchTouchEvent]ev=ACTION_DOWN 06-07 20:27:57.449 28523-28523/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->onInterceptTouchEvent]ev=ACTION_DOWN 06-07 20:27:57.449 28523-28523/com.example.demos I/songzheweiwang: [ViewInner-->dispatchTouchEvent]event=ACTION_DOWN 06-07 20:27:57.449 28523-28523/com.example.demos I/songzheweiwang: [ViewInner-->onTouchEvent]event=ACTION_DOWN 06-07 20:27:57.449 28523-28523/com.example.demos I/songzheweiwang: [ViewGroupMiddle-->onTouchEvent]event=ACTION_DOWN 06-07 20:27:57.449 28523-28523/com.example.demos I/songzheweiwang: [ViewGroupOuter-->onTouchEvent]event=ACTION_DOWN 06-07 20:27:57.450 28523-28523/com.example.demos I/songzheweiwang: [EventDemoActivity-->onTouchEvent]event=ACTION_DOWN 06-07 20:27:57.514 28523-28523/com.example.demos I/songzheweiwang: [EventDemoActivity-->dispatchTouchEvent]ev=ACTION_UP 06-07 20:27:57.515 28523-28523/com.example.demos I/songzheweiwang: [EventDemoActivity-->onTouchEvent]event=ACTION_UP
这四次触摸事件的日志结果用空格隔开,分析该 log 能够发现:当点击 Boss 区域时,里面的三个控件均未触发事件;当点击 PM 区域时,Team Leader 和 Programmer 中的没有任何动做;点击 Team Leader 区域时,只有 Programmer 没有触发任何事件;当点击 Programmer 区域时,4 个角色均被触发。那么这个结论就很显而易见了:当点击到 View 系统的某一层时,事件从外往内传递时,只到被点击的那一层为止,不会再派发到其子 View 中。这 4 个场景,是否是和咱们开篇第一节中提到的 4 种场景很类似呢?点击到哪一个区域,说明本来安排的任务自己就应该由该职位的人来完成,其手下就彻底能够当成是不存在的。
到目前为止,Android 的事件分发和传递机制就分析完了。本文中 Touch 事件的 3 个主要方法返回值均有 3 种情形,因此会有多种逻辑处理组合。这里选取了中间层 ViewGroupMiddle 来举例,只是做为表明来分析,笔者彻底能够经过其它的组合来分析更多的可能状况。若是分析中有不稳当或者不许确的地方,欢迎来拍砖
Android 自定义View篇(一)View绘制流程
Android 自定义View篇(二)Canvas详解
Android 自定义View篇(三)Paint详解
Android 自定义View篇(四)自定义属性详解