Android事件的分发机制

PhoneWindow的结构

Activity有一个PhoneWindow类型的成员变量mWindow,PhoneWindow是每一个Activity的主窗口类,PhoneWindow里面有一个DecorView类型的成员变量mDecor。
DecorView继承自FrameLayout,我们通过setContentView所设置进去的内容是在id为content的ViewGroup下的,这个ViewGroup和DecorView之间有一些额外的布局,比如ActionBar等,不同的UI风格,额外的布局是不一样的

容易混淆的方法名字

Android事件的分发机制_第1张图片

Android事件的分发机制_第2张图片

在看源码的过程中,如果没有弄清楚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事件的分发机制_第3张图片

我们可以看到这是一个递归算法,理解的要点
第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的范围内

你可能感兴趣的:(android)