阅读此篇文章需要了解Activity和Window相关知识
按照惯例首先说两个知识点
1,一个完整的事件是有一个Down ,N个Move,一个Up组成,Move的个数可以为 0。
2,View分为两种,第一种可以有子View的 直接或者间接继承ViewGroup,另一种不允许有子View的,直接或者间接继承View的。TextView,ImageView等等。
开始介绍,当我们一个事件到屏幕上,怎么传到我们的View上面呢,分两部分
1,经过物理屏幕层获取,然后封装成程序能识别的事件,然后通过跨进程通信传到正在展示的Activity上,(这一层我是猜想的,但是我觉得八九不离十,这一层我们无需要关心,这个是手机系统做的)。
2,这个事件传送到我们的Activity上,然后在当前Activity中分发(这个是我们关心的,是我们开发常用的主要介绍这个)。
简单说一下Activity的组成,每个Activity包含一个window,每个window都是一个phoneWindow,每个PhoneWindow包含一个DecorView,每一个DecorView都是一个Framelayout。
简单总结一下,Activity 和DecorView通过window对象连接起来,A持有W,W持有D,所以一个Activity的布局最外层就是DecorView。
上边说了,事件首先到Activity上,所以我们从Activity的分发方法看。

Activity
1,如果是down,说明是一个新的事件,初始化UI(空实现方法,没有太大实际意义)
2,A调用W的superDispatchTouchEvent 方法,把事件从Activity 分发到DecorView。
3,返回Activity的onTouchEvent。
这个方法主要的作用,把事件从Activity分发到的从DecorView。


通过这两个方法把事件分发到了decorView的这个方法super.dispatchTouchEvent(event),因为前边说过decorView是Framelayout,所以调用的就是

到这里事件已经分发到我们的decorView了,这里都是系统源码,我们一般不能改变的。
回到上边说的View一共两种类型,第一种直接或者间接继承ViewGroup的,第二种直接或者间接继承View
首先看第一种也就是ViewGroup的dispatchTouchEvent方法,代码太长不上了简述流程
ViewGroup的分发方法主要作用是确定那个View消费事件
1,判断是否进行事件拦截,
2,根绝拦截方法的返回结果进行处理
如果进行了拦截,则会调用到super.dispatchTouchEvent(event),最终会调用到View类的dispatchTouchEvent(event)
如果没有进行拦截,则会对自己内部的所有子View进行判断,是否有焦点,是否在事件坐标范围之内等等一些列,然后调用该View的dispatchTouchEvent(event)(这里补充一下,这个子View可以是ViewGroup类型的也可以是View类型的。所以如果是viewGroup类型的还会把这个流程走一遍,直到找到我们需要的View)
第二种就是View的dispatchTouchEvent方法,一样简述流程
View类型的分发方法和ViewGroup的作用不一样,主要是确定怎么消费事件
1,判断mOnTouchListener.onTouch(this, event)的返回值,
如果返回true,后边onTouchEvent(event)就不会响应了。
如果返回false,则会调用onTouchEvent(event)消费事件
2,ontouchEvent把事件分成四种类型
第一种down,处理一些标记。post一个长按事件到队列当中,长按就开始计时,超过这个阀值长按事件就会响应。
第二种 move,如果有move事件,则移除点击和长按的事件标记,(很好理解如果滑动了就不能是点击或者长按了)
第三种 canle,和Move事件差不多,细节的区别,移除点击和长按的事件标记,(很好理解如果取消了就不能是点击或者长按了)
第四种up,如果能够到这里,把之前的所以标记移除,然后进行事件消费,但这里有个细节(会根据长按的返回值去决定是否执行单击的回调 )
总结一下
1,ontouch 优先级高于一切最先执行,然会true后边事件得不到执行,。
2,长按事件,down的时候就开始计时,超过阀值就行执行,这是一个handler 队列事件,如果长按回调返回true,单击事件则得不到相应。
3,单击事件优先级最低,在up的时候才会执行,还会根据长按的返回值判断是否执行,也是一个队列事件。
最后总结一下
事件分发的核心就是找到需要消费事件的View,然后根据对事件进行消费。也就是ViewGroup类的分发事件主要做的就是找到消费的目标,View类的分发事件主要做的是怎么处理事件。一个事件经过分发找到处理事件的View后,调用该View的分发方法,最终调用到View类的分发方法消费掉事件。
至于拦截事件 这个就是看一个返回值,需要我们根据实际灵活发挥。

网友评论