Android进阶——Android事件分发机制之dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent 前言Android事件分发机制可以说是我们Android工程师面试题中的必考题,弄懂它的原理是我们避不开的任务,所以长痛不如短痛,花点时间干掉他,废话不多说,开车啦Android事件分发机制的简介Android事件分发机制的发生在View与View之间或者ViewGroup与View之间具有镶嵌的视图上,而且视图上必须为点击可用。
当一个点击事件产生后,它的传递过程遵循如下顺序:Activity->Window->View,即事件先传递给Activity,再到Window,再到顶级View,才开始我们的事件分发Android事件分发机制的相关概念Android事件分发机制主要由三个重要的方法共同完成的dispatchTouchEvent:用于进行点击事件的分发onInterceptTouchEvent:用于进行点击事件的拦截onTouchEvent:用于处理点击事件这里需要注意的是View中是没有onInterceptTouchEvent()方法的Android事件分发机制的分发例子这里以两个ViewGroup嵌套View来演示,下面是演示图一、MyView继承View并覆写其三个构造方法,覆写dispatchTouchEvent和onTouchEvent,前面已经说了View是没有onInterceptTouchEvent方法的public class MyView extends View {public MyView(Context context) {super(context);}public MyView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}public MyView(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {System.out.println("MyView dispatchTouchEvent");return super.dispatchTouchEvent(event);}@Overridepublic boolean onTouchEvent(MotionEvent event) {System.out.println("MyView onTouchEvent");return super.onTouchEvent(event);}}二、MyViewGroup01和MyViewGroup02MyViewGroup01和MyViewGroup02是一样的代码,这里以01为例,继承ViewGroup并覆写其三个构造方法,覆写dispatchTouchEvent和onTouchEvent和onInterceptTouchEvent方法public class MyViewGroup01 extends LinearLayout {public MyViewGroup01(Context context) {super(context);}public MyViewGroup01(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr);}public MyViewGroup01(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {System.out.println("MyViewGroup01 dispatchTouchEvent");return super.dispatchTouchEvent(ev);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {System.out.println("MyViewGroup01 onInterceptTouchEvent");return super.onInterceptTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent event) {System.out.println("MyViewGroup01 onTouchEvent");return super.onTouchEvent(event);}}三、MyView和MyViewGroup布局文件这里以ViewGroup和Group嵌套,由上面可以知道事件最后分配到布局的顶级View,这里的顶级View是MyViewGroup02,然后开始事件的传递<?xml version="1.0" encoding="utf-8"?><com.handsome.boke2.TouchEvent.MyViewGroup02xmlns:android="/apk/res/android"android:layout_width="200dp"android:layout_height="200dp"android:background="#0f0"><com.handsome.boke2.TouchEvent.MyViewGroup01android:layout_width="100dp"android:layout_height="100dp"android:background="#f00"><com.handsome.boke2.TouchEvent.MyViewandroid:layout_width="50dp"android:layout_height="50dp"android:background="#00f" /></com.handsome.boke2.TouchEvent.MyViewGroup01></com.handsome.boke2.TouchEvent.MyViewGroup02>四、分析事件传递点击MyView(即蓝色部分):其事件会从顶级View(MyViewGroup02)往下分发,而事件的分发过程中分为两步骤分发过程处理过程其正常的分发事件结果为//分发过程MyViewGroup02 dispatchTouchEventMyViewGroup02 onInterceptTouchEventMyViewGroup01 dispatchTouchEventMyViewGroup01 onInterceptTouchEventMyView dispatchTouchEvent//处理过程MyView onTouchEventMyViewGroup01 onTouchEventMyViewGroup02 onTouchEvent1、dispatchTouchEvent(分发事件)如果在MyViewGroup01的dispatchTouchEvent方法中返回true,表示需要在MyViewGroup01消费了整个事件,即不会再分发,也不会再处理。
dispatchTouchEvent方法中返回true的打印信息//分发过程MyViewGroup02 dispatchTouchEventMyViewGroup02 onInterceptTouchEventMyViewGroup01 dispatchTouchEvent如果在MyViewGroup01的dispatchTouchEvent方法中返回false,表示在MyViewGroup01点击事件在本层不再继续进行分发,并交由上层控件的onTouchEvent方法进行消费。
dispatchTouchEvent方法中返回false的打印信息//分发过程MyViewGroup02 dispatchTouchEventMyViewGroup02 onInterceptTouchEventMyViewGroup01 dispatchTouchEvent//处理过程MyViewGroup02 onTouchEvent2、onInterceptTouchEvent(拦截事件)如果在MyViewGroup01的onInterceptTouchEvent方法中返回true,表示需要在MyViewGroup01拦截这个点击事件,不再继续往下分发,即MyView不再执行dispatchTouchEvent方法。
但是只是分发结束了而已,接着开始处理事件。
下面是onInterceptTouchEvent方法中返回true的打印信息//分发过程MyViewGroup02 dispatchTouchEventMyViewGroup02 onInterceptTouchEventMyViewGroup01 dispatchTouchEventMyViewGroup01 onInterceptTouchEvent//处理过程MyViewGroup01 onTouchEventMyViewGroup02 onTouchEvent如果在MyViewGroup01的onInterceptTouchEvent方法中返回false,表示需要在MyViewGroup01不会拦截这个点击事件,继续往下分发。
下面是onInterceptTouchEvent方法中返回false的打印信息//分发过程MyViewGroup02 dispatchTouchEventMyViewGroup02 onInterceptTouchEventMyViewGroup01 dispatchTouchEventMyViewGroup01 onInterceptTouchEventMyView dispatchTouchEvent//处理过程MyView onTouchEventMyViewGroup01 onTouchEventMyViewGroup02 onTouchEvent3、onTouchEvent(消费事件)如果MyViewGroup01的onTouchEvent方法中返回true,表示MyViewGroup01可以将该事件直接消费掉了,即分发结束后,处理事件的时候,直接处理到MyViewGroup01就可以结束了。