🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
#### **七、事件拦截机制分析** **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方法尽管是事件分发的第一步,但是一般不改写这个方法,我们将上面的流程再形象一点如下图所示