概述
Android事件分发也属于Android的基础,我尝试用自己的话来叙述一下,结果说不出来…能理解,但是不能说,只能说是不太熟悉。还是写一篇文章来记录一下吧。
使用场景

在View与View之间嵌套的时候,通常要处理事件的分发,判断是否拦截或是下发一个事件。
事件作用于View,分发的对象是对触摸屏幕产生的事件,让该事件在具体View上产生作用。
所以,分发的对象是:点击事件。作用的对象是:Activity,ViewGroup,View。
分发的顺序是:Activity ——> ViewGroup ——> View
事件类型
MotionEvent.ACTION_DOWN 按下View(所有事件的开始)
MotionEvent.ACTION_UP 抬起View(与DOWN对应)
MotionEvent.ACTION_MOVE 滑动View
MotionEvent.ACTION_CANCEL 结束事件(非人为原因)
方法
dispatchTouchEvent:
用来进行事件的分发。
如果事件能够被传递给当前View,那么此方法一定会被调用,返回结果受到当前View的onTouchEvent和下级View的dispatchTouchEvent方法影响,表示是否消耗当前事件。onInterceptTouchEvent:
会在dispatchTouchEvent方法内部调用,用来判断是否拦截某个事件,如果当前View拦截了某个事件(返回true),那么在同一个事件序列当中,此方法不会再次被调用,返回结果表示是否拦截当前事件。onTouchEvent:
在dispatchTouchEvent方法中调用,用来处理事件,返回结果表示是否消耗当前事件,如果不消耗(返回false),则在同一个事件序列中,当前View无法再次接收到后续的事件队列
onTouchEvent默认的返回值由clickable和longClickable共同决定,只要有一个为true,onTouchEvent的返回值就是true,longClickable的默认值都为false,clickable的默认值分情况,Button为true,TextView为false。Activity中的事件分发
传递点击事件,当事件能够传递给当前View的时候,该方法就会被调用
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106/*** 源码分析:Activity.dispatchTouchEvent()*/public boolean dispatchTouchEvent(MotionEvent ev) {// 一般事件列开始都是DOWN事件 = 按下事件,故此处基本是trueif (ev.getAction() == MotionEvent.ACTION_DOWN) {onUserInteraction();// ->>分析1}// ->>分析2if (getWindow().superDispatchTouchEvent(ev)) {return true;// 若getWindow().superDispatchTouchEvent(ev)的返回true// 则Activity.dispatchTouchEvent()就返回true,则方法结束。即 :该点击事件停止往下传递 & 事件传递过程结束// 否则:继续往下调用Activity.onTouchEvent}// ->>分析4return onTouchEvent(ev);}/*** 分析1:onUserInteraction()* 作用:实现屏保功能* 注:* a. 该方法为空方法* b. 当此activity在栈顶时,触屏点击按home,back,menu键等都会触发此方法*/public void onUserInteraction() {}// 回到最初的调用原处/*** 分析2:getWindow().superDispatchTouchEvent(ev)* 说明:* a. getWindow() = 获取Window类的对象* b. Window类是抽象类,其唯一实现类 = PhoneWindow类;即此处的Window类对象 = PhoneWindow类对象* c. Window类的superDispatchTouchEvent() = 1个抽象方法,由子类PhoneWindow类实现*/public boolean superDispatchTouchEvent(MotionEvent event) {return mDecor.superDispatchTouchEvent(event);// mDecor = 顶层View(DecorView)的实例对象// ->> 分析3}/*** 分析3:mDecor.superDispatchTouchEvent(event)* 定义:属于顶层View(DecorView)* 说明:* a. DecorView类是PhoneWindow类的一个内部类* b. DecorView继承自FrameLayout,是所有界面的父类* c. FrameLayout是ViewGroup的子类,故DecorView的间接父类 = ViewGroup*/public boolean superDispatchTouchEvent(MotionEvent event) {return super.dispatchTouchEvent(event);// 调用父类的方法 = ViewGroup的dispatchTouchEvent()// 即 将事件传递到ViewGroup去处理,详细请看ViewGroup的事件分发机制}// 回到最初的调用原处/*** 分析4:Activity.onTouchEvent()* 定义:属于顶层View(DecorView)* 说明:* a. DecorView类是PhoneWindow类的一个内部类* b. DecorView继承自FrameLayout,是所有界面的父类* c. FrameLayout是ViewGroup的子类,故DecorView的间接父类 = ViewGroup*/public boolean onTouchEvent(MotionEvent event) {// 当一个点击事件未被Activity下任何一个View接收 / 处理时// 应用场景:处理发生在Window边界外的触摸事件// ->> 分析5if (mWindow.shouldCloseOnTouch(this, event)) {finish();return true;}return false;// 即 只有在点击事件在Window边界外才会返回true,一般情况都返回false,分析完毕}/*** 分析5:mWindow.shouldCloseOnTouch(this, event)*/public boolean shouldCloseOnTouch(Context context, MotionEvent event) {// 主要是对于处理边界外点击事件的判断:是否是DOWN事件,event的坐标是否在边界内等if (mCloseOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN&& isOutOfBounds(context, event) && peekDecorView() != null) {return true;}return false;// 返回true:说明事件在边界外,即 消费事件// 返回false:未消费(默认)}
ViewGroup中的事件分发
|
|
View事件的分发机制
|
|
文字总结

当一个事件在屏幕上产生时,首先由Activity的dispatchTouchEvent传递到ViewGroup(一般不会在Activity里就直接拦截),该事件首先要在ViewGroup的dispatchTouchEvent方法中进行判断是否拦截,如果拦截就直接在ViewGroup中消费,不会传递到子View,如果不拦截则通过遍历的方式找到点击的控件View,并将事件传递从ViewGroup传递到View中。
事件在View也是首先调用dispatchTouchEvent方法,该方法会返回boolean值,会返回到ViewGroup中,如果为true则ViewGroup的touch事件拦截(即ViewGroup后面的代码不会执行)。事件也会在View中消费掉。这里的消费是是指调用了当前的touch事件,会不会调用click还看情况。