#### **七、事件拦截机制分析**
**1、什么是触摸事件**
触摸事件顾名思义就是捕获触摸后产生的事件。当点击一个按钮时,通常就会产生两个或三个事件:
* 按钮按下——事件一
* 如果不小心滑动了一点——事件二
* 当手抬起——事件三
Android为触摸事件封装了一个类——[MotionEvent](https://www.androidos.net.cn/android/5.0.1_r1/xref/frameworks/base/core/java/android/view/MotionEvent.java),这个类很重要,只要是重写触摸相关的方法,参数一般都含有MotionEvent。
首先我们先看一下这个类的源码树结构,如图
![](https://box.kancloud.cn/2776da1db10b68d202e77be84c12a033_393x662.jpg)
![](https://box.kancloud.cn/7040d215b203fde9f42f2a9d38497fcb_341x819.jpg)
![](https://box.kancloud.cn/c2da8751837b1aea3dc6b70ef1bdfef0_376x805.jpg)
![](https://box.kancloud.cn/7775936bdb4258865d2a8c4573505c4b_365x837.jpg)
![](https://box.kancloud.cn/ef8fdcabdc52e7c6fbae1548e4cfe705_784x861.jpg)
![](https://box.kancloud.cn/d8e26f90b030817f230dd3a6e482dac7_373x778.jpg)
![](https://box.kancloud.cn/975b75f56f678abdab1a7e3143e9bd8b_370x880.jpg)
触摸事件其实就是一个工作类型加坐标而已,但是Android的view结构是树形结构,可能层层嵌套,一层层地堆叠起来的,那触摸事件到底改分给谁呢?同一事件子view和父ViewGroup都有可能想要进行处理,这就产生了事件拦截。
**2、实例分析事件拦截机制**
一个总经理——MyViewGroupA,最外层的ViewGroup
一个部长——MyViewGroupB,中间的ViewGroup
一个底层人民,干活的你——MyView,在最底层。
布局文件[activity_main.xml](https://github.com/xuyisheng/AndroidHeroes/blob/master/3.Android控件架构/ViewLayout/app/src/main/res/layout/activity_main.xml)如下所示
~~~
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<com.imooc.viewlayout.MyViewGroupA
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_blue_bright">
<com.imooc.viewlayout.MyViewGroupB
android:layout_width="300dp"
android:layout_height="300dp"
android:background="@android:color/holo_green_dark">
<com.imooc.viewlayout.MyView
android:layout_width="150dp"
android:layout_height="150dp"
android:background="@android:color/darker_gray" />
</com.imooc.viewlayout.MyViewGroupB>
</com.imooc.viewlayout.MyViewGroupA>
</RelativeLayout>
~~~
[MainActivity.java](https://github.com/xuyisheng/AndroidHeroes/blob/master/3.Android控件架构/ViewLayout/app/src/main/java/com/imooc/viewlayout/MainActivity.java)
~~~
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
~~~
通过点击三个布局中的View,打印log来研究事件拦截机制。
**①、分析**
对于ViewGroup来说,重写以下三个方法
~~~
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.d("xys", "ViewGroupA dispatchTouchEvent event.getAction()= " + ev.getAction());
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.d("xys", "ViewGroupA onInterceptTouchEvent event.getAction()= " + ev.getAction());
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d("xys", "ViewGroupA onTouchEvent event.getAction()= " + event.getAction());
return super.onTouchEvent(event);
}
~~~
对于View来说,重写以下两个方法
~~~
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d("xys", "View onTouchEvent event.getAction()= " + event.getAction());
return super.onTouchEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.d("xys", "View dispatchTouchEvent event.getAction()= " + event.getAction());
return super.dispatchTouchEvent(event);
}
~~~
从上面的代码就得知,ViewGroup级别较高,比View多一个方法onInterceptTouchEvent(),从字面就能猜到这个方法是事件拦截的核心方法。
首先,我们点击最里面的View(MyView)打印log如下所示
~~~
02-06 00:20:03.450 2763-2763/com.imooc.viewlayout D/xys: ViewGroupA dispatchTouchEvent event.getAction()= 0
02-06 00:20:03.451 2763-2763/com.imooc.viewlayout D/xys: ViewGroupA onInterceptTouchEvent event.getAction()= 0
02-06 00:20:03.451 2763-2763/com.imooc.viewlayout D/xys: ViewGroupB dispatchTouchEvent event.getAction()= 0
02-06 00:20:03.451 2763-2763/com.imooc.viewlayout D/xys: ViewGroupB onInterceptTouchEvent event.getAction()= 0
02-06 00:20:03.451 2763-2763/com.imooc.viewlayout D/xys: View dispatchTouchEvent event.getAction()= 0
02-06 00:20:03.451 2763-2763/com.imooc.viewlayout D/xys: View onTouchEvent event.getAction()= 0
02-06 00:20:03.453 2763-2763/com.imooc.viewlayout D/xys: ViewGroupB onTouchEvent event.getAction()= 0
02-06 00:20:03.455 2763-2763/com.imooc.viewlayout D/xys: ViewGroupA onTouchEvent event.getAction()= 0
~~~
可以得出正常情况下,
* 时间的传递顺序是:
**总经理(MyViewGroupA)→部长(MyViewGroupB)→你(MyView)。**
**事件传递时先执行dispatchTouchEvent方法,再执行onInterceptTouchEvent方法。**
* 事件处理的顺序:
**你(MyView)→部长(MyViewGroupB)→总经理(MyViewGroupA)。**
**事件处理都是执行onTouchEvent 方法**
* 事件传递的返回值
**True,拦截,不继续;False,不拦截,继续流程**
* 事件处理的返回值
**True,处理了,不用审核了;False,给上级处理。**
初始情况下,返回值都是False。
一般情况下,在事件传递过程中,只关心onInterceptTouchEvent方法,而dispatchTouchEvent方法尽管是事件分发的第一步,但是一般不改写这个方法,我们将上面的流程再形象一点如下图所示