Android事件的分发机制

PhoneWindow的结构 Activity有一个PhoneWindow类型的成员变量mWindow,PhoneWindow是每一个Activity的主窗口类,PhoneWindow里面有一个DecorView类型的成员变量mDecor。
DecorView继承自FrameLayout,我们通过setContentView所设置进去的内容是在id为content的ViewGroup下的,这个ViewGroup和DecorView之间有一些额外的布局,比如ActionBar等,不同的UI风格,额外的布局是不一样的
容易混淆的方法名字 【Android事件的分发机制】Android事件的分发机制
文章图片

Android事件的分发机制
文章图片

在看源码的过程中,如果没有弄清楚xxxTouchEvent方法的作用是什么、它是哪个类的方法、他是父类的方法还是被重载的方法,那么就很容易弄得云里雾里,找不清楚方向,我把涉及的主要方法画在了上面两个图中。
dispatchTouchEvent: ViewGroup的此方法作用是向它的子View分发事件,View的此方法作用是处理onTouch和onTouchEvent的调用
onInterceptTouchEvent:此方法是ViewGroup的方法,在此方法中可以拦截要传递给子View的事件
onTouch:是OnTouchListener的方法,调用时机先于onTouchEvent,如果在此方法中返回了true,那么onTouchEvent就收不到事件
onTouchEvent:是View的方法,在此方法中处理具体的DOWN、UP、MOVE事件,判断是否形成了click、long click等,如果判断到形成了click事件,那么就会调用OnClickListener的onClick方法
最精简的伪代码描述事件分发算法 android事件分发的代码很多而且庞杂,我把它用最精简的伪代码描述如下,当然这只代表最主干的情况,代表的是普通的一根手指按下又弹起的情况的描述
Android事件的分发机制
文章图片

我们可以看到这是一个递归算法,理解的要点
第13行,这里的child有两种情况,如果是ViewGroup,那么就是对dispatchTouchEvent的递归调用,它的返回值代表了它所代表的子树是否要处理这个事件;如果View,它调用dispatchTouchEvent的作用就是处理onTouch和onTouchEvent的调用顺序
第20行,如果判断到要截获事件,那么这个事件就直接给了当前ViewGroup的父类的dispatchTouchEvent方法,而ViewGroup的父类是谁?就是View,所以这里调用的dispatchTouchEvent就是去真正地在叶子节点处理touch事件了
第24行,代表的是自己不截获且所有子View都不处理的情况,这个时候就交给自己处理,如果自己还不处理?handled就会为false,继续给上一级父亲处理
子View是如何判断是否要处理事件的?

protected boolean isTransformedTouchPointInView(float x, float y, View child, PointF outLocalPoint) { final float[] point = getTempPoint(); point[0] = x; point[1] = y; transformPointToViewLocal(point, child); final boolean isInView = child.pointInView(point[0], point[1]); if (isInView && outLocalPoint != null) { outLocalPoint.set(point[0], point[1]); } return isInView; }public void transformPointToViewLocal(float[] point, View child) { point[0] += mScrollX - child.mLeft; point[1] += mScrollY - child.mTop; if (!child.hasIdentityMatrix()) { child.getInverseMatrix().mapPoints(point); } }final boolean pointInView(float localX, float localY) { return localX >= 0 && localX < (mRight - mLeft) && localY >= 0 && localY < (mBottom - mTop); }

我们可以看到所谓的transformTouchEvent就是把绝对坐标转换到view的相对坐标,怎么判断view要不要处理事件?判断相对坐标是不是在子view的范围内

    推荐阅读