Android进阶之事件拦截处理机制

1 Android控件架构 Android进阶之事件拦截处理机制
文章图片

Android进阶之事件拦截处理机制
文章图片

Android进阶之事件拦截处理机制
文章图片

1 简单的总结 (1)父View优先拦截当前事件,拦截不成功就让子View对当前事件进行拦截。
(2)如果拦截成功的话,就会沿着子view到父View的路径查找onTouchEvent返回true的那个子View,让该子View对该事件进行处理;
(3)同时如果某一个View对当前事件拦截成功的话,当前事件就不会继续分发给这个View的子View。
2 事件分发与处理 2.1 结论
(1)android对事件分发的顺序为:Activity–>PhoneWindow->DecorView->yourView;
(2)android控件对事件处理的优先级:onTouch>onTouchEvent>onClick
2.2 事件分发
android既然可以对事件进行拦截,肯定有某个方法对事件进行的传递或者分发。完成事件分发功能的方法由Activity的dispatchTouchEvent(MotionEvent ev)l来负责:

public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { //该方法为空方法,直接忽略之 onUserInteraction(); } //把事件ev交给phoneWindow来处理 if (getWindow().superDispatchTouchEvent(ev)) { //表明整个事件到此结束,处理完毕 return true; } //说明该事件在View中没有得到处理,由Activity自己处理 //至于怎么处理博客后面后有说明 return onTouchEvent(ev); }

PhoneWindow方法都做了些什么:
@Override public boolean superDispatchTouchEvent(MotionEvent event) { return mDecor.superDispatchTouchEvent(event); }

就是把此次事件直接很光棍的传给DecorView,这个View是所有视图的根视图,Activity界面中你能见到的各个View都是DecorView的子View。
2.3 事件处理
到此为止事件已经分发到View上面,View获取到事件后有两个选择:处理和不处理该事件,如果处理该事件那事件就不会继续向其子View分发下去;否则就继续分发下去交给子View对该事件做同样的判断,其实就是个递归的过程。
先用如下的伪代码也表示一下事件处理流程:
public boolean dispatchTouchEvent(event){ //如果当前View对此事件拦截成功 if(this.onInterceptTouchEvent(event)){ //由当前View对此事件进行处理 //true 表示处理了该事件,false表示没有处理该事件 return onTouchEvent(event); }else{//没有拦截成功 //交给子类来分发拦截处理 return child.dispatchTouchEvent(event); } }

更直观的用流程图可以如下表示:
Android进阶之事件拦截处理机制
文章图片

其实通过上面的代码也可以得出这个结论:当Activity中所有的视图View都不处理该事件的是就交给Activity的onTouchEvent方方来处理。
2.4 分析ViewGroup分发事件
(1)ViewGroup永远不会对拦截,因为他的onInterceptTouchEvent(MotionEvent ev)始终返回的是false!这样DecorView对到来的事件MotionEvent就只有分发到子View并由子View进行拦截和处理此事件了.
(2)View包括直接继承于View的子类因为其父类View没有onInterceptTouchEvent方法,所以没法对事件进行拦截,如果这种View获取到了事件,那么就会执行onTouchEvent方法。
3 图例解析 3.1 情况1
如果A的InterceptTouchEvent返回了true,其余的仍然返回false,那么执行输出的log为:
Android进阶之事件拦截处理机制
文章图片

转换成效果图为:
Android进阶之事件拦截处理机制
文章图片

可以发现此时A拦截了此次Touch事件,事件不再向A的子控件B、C、D传递。此时所有的action事件比如手指移动ACTION_MOVE或者ACTION_UP等事件都交给A的onTouchEvent方法去处理(当然这是在onTouchEvent方法返回true的情况下,如果返回false经过测试时不会相应这些action的)。B、C、D控件是的事件处理拦截方法和事件处理方法是无法得到执行的。
3.2 情况2
只有B的onIntercepteTouchEvent事件返回了true的情况下,打印的log为
Android进阶之事件拦截处理机制
文章图片

转换成效果图为:
Android进阶之事件拦截处理机制
文章图片

3.3 情况3
同理可知,C控件的onIntercept方法返回了true的情况下,其余的仍然返回false的情况下,输出log为
Android进阶之事件拦截处理机制
文章图片

转换成效果图为
Android进阶之事件拦截处理机制
文章图片

3.4 下面说说各个view的onTouchEvent返回true的情况
由于onTouchEvent事件是从子控件到父控件传递的,当D的onTouchEvent返回true的时候,经测试输出效果如下
Android进阶之事件拦截处理机制
文章图片

转换成效果图为:
Android进阶之事件拦截处理机制
文章图片

经过测试发现,此时D处理了此次Touch事件的各种action,C B D是的onTouchEvent的没有得到执行。
同理当C的onTouchEvent方法返回了true的时候,输出的log如下
Android进阶之事件拦截处理机制
文章图片

转换成效果图如下:
Android进阶之事件拦截处理机制
文章图片

4 参考链接 android事件拦截处理机制详解
从源码角度分析android事件分发处理机制
【Android进阶之事件拦截处理机制】 Android群英传笔记——第三章:Android控件架构与自定义控件讲解

    推荐阅读