android view的事件体系(三)
android 事件分发机制的源码分析
1.Activity对点击事件的分发过程
当一个点击操作发生时,事件最先传递给当前的activity,由activity的dispatchTouchEvent来进行派发,
具体工作由activity内部的window完成,window会将事件传递给decorView,通过Activity.getWindow.getDecorView();可以获得
2.源码分析
1.Activity的dispatchTouchEvent:
如果返回true,整个事件循环结束,返回false相当于事件没人处理,所有的View的onTOuchEvent都会返回false,activity的onTouchEvent就会被调用;
2.Activity如何将事件传递给viewGroup的
由于事件是交给activity所附属的window进行分发,window是一个抽象类,window的superDispatchTouchEvent方法也是抽象方法;
由于window唯一实现类是phoneWindow,所以查看phoneWindow源码:
上诉代码:phoneWindow将事件直接传递给decorView;
事件传递到decorView里,由于decorView继承FrameLayout且是父view,所以事件最终会传递给View;
我们要关注的重点是:事件到了view之后如何传递,一般来说顶级视图view都是viewGroup;
3.顶级视图view对点击事件的分发过程;
点击事件到达顶级视图view以后,会调用viewGroup的dispatchTouchEvent方法,如果顶级viewGroup拦截事件,onInterceptTouchEvent返回true;事件由ViewGroup处理,如果顶级viewGroup不拦截事件,则事件会传递给他所在的点击事件的子view,这时子view的dispatchTouchEvent会被调用,事件已经从顶级view传递给下一层view,接下来的传递过程和顶级view是一致的,如此循环完成这个事件的分发;
ViewGroup的dispatchTouchEvent方法 分析:
从上诉代码中可以看出:
viewGroup在如下两种情况会判断是否要拦截当前事件;事件类型为ACTION_DOWN或者mFirstTouchTarget!= null. 当事件由viewGroup的子元素成功处理时,mFirstTouchTarget会被赋值并指向子元素; 由于上诉条件为false,将导致viewGroup的onInterceptTouchEvent不会被调用。
如果viewGroup不拦截事件的时候,事件会向下分发到他的子view进行处理:
在上面代码中child传递的不是null,因此他会直接调用子元素的dispatchTouchEvent方法,这样事件就交由子元素处理
如果子元素的第三patchTouchEvent返回true,暂时不用考虑事件在子元素内部怎么发生的,那么mFristTouchTarget就会跳出for循环;
这段代码:这里的第三个参数child为null,前面分析,他会调用super.dispatchTouchEvent(event),
这里就跳到了view的dispatchTouchEvent方法,将事件交给view来进行处理;
4.view对点击事件的处理
先看dispatchTouchEvent方法:
上诉源码中: 首先判断onTouchListener 中的onTOUch方法返回true,那么onTouchEvent就不会被调用,
接下来看onTOuchEvent的实现:
很显然。不可用状态下的view照样会消耗点击事件,
只要view的CLICKABLE 和 LONG_CLICKABLE 有一个为true,那么就会消耗事件,即onTOuchEvent方法返回true; 反之就不会消耗事件,交给他的父级处理;
android view的事件体系(二)