(二)Android事件分发机制 - ViewGroup篇

2017-08-28  本文已影响0人  DevWang

本文适用于对Android事件分发机制有一定基础的开发者阅读,主要是通过对ViewGroup类中的事件分发、事件拦截的源代码进行解析以达到完全理解其原理的目的

我们知道ViewGroup中包含dispatchTouchEventonInterceptTouchEventonTouchEvent方法,接下来我们通过源代码(基于Android6.0)看看这些方法内部到底做了哪些事情。

ViewGroup#dispatchTouchEvent源码解析

初始化ACTION_DOWN事件
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    ...
    if (actionMasked == MotionEvent.ACTION_DOWN) {
            // 这里会将mFirstTouchTarget置为 null
            cancelAndClearTouchTargets(ev);
            resetTouchState();
    }
    ...
}
检查ViewGroup是否要拦截事件
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    ...
    final boolean intercepted;
    if (actionMasked == MotionEvent.ACTION_DOWN
            || mFirstTouchTarget != null) {
        final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
        if (!disallowIntercept) {
            intercepted = onInterceptTouchEvent(ev);
            ev.setAction(action); // restore action in case it was changed
        } else {
            intercepted = false;
        }
    } else {
        // There are no touch targets and this action is not an initial down
        // so this view group continues to intercept touches.
        intercepted = true;
    }
    ...
    // Check for cancelation.
    final boolean canceled = resetCancelNextUpFlag(this)
            || actionMasked == MotionEvent.ACTION_CANCEL;
    // ...
}

public boolean onInterceptTouchEvent(MotionEvent ev) {
    return false;
}
对ACTION_DWON事件的特殊处理

接下来是一个If判断语句,内部还有若干if语句,以下先省略所有if体的内容,我们从大体上认识这块代码的作用:

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    ...
    TouchTarget newTouchTarget = null;
    boolean alreadyDispatchedToNewTouchTarget = false;
    if (!canceled && !intercepted) {
        ...// IF体1
        if (actionMasked == MotionEvent.ACTION_DOWN
                    || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
                    || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
            ...// IF体2
        }
    }
    ...
}

小结:

对除了ACTION_DOWN之外的其他事件的处理
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    ...
    // Dispatch to touch targets.
    if (mFirstTouchTarget == null) {
        // No touch targets so treat this as an ordinary view.
        handled = dispatchTransformedTouchEvent(ev, canceled, null,
                TouchTarget.ALL_POINTER_IDS);
    } else {
        // Dispatch to touch targets, excluding the new touch target if we already
        // dispatched to it.  Cancel touch targets if necessary.
        TouchTarget predecessor = null;
        TouchTarget target = mFirstTouchTarget;
        while (target != null) {
            final TouchTarget next = target.next;
            if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
                handled = true;
            } else {
                final boolean cancelChild = resetCancelNextUpFlag(target.child)
                        || intercepted;
                if (dispatchTransformedTouchEvent(ev, cancelChild,
                        target.child, target.pointerIdBits)) {
                    handled = true;
                }
                if (cancelChild) {
                    if (predecessor == null) {
                        mFirstTouchTarget = next;
                    } else {
                        predecessor.next = next;
                    }
                    target.recycle();
                    target = next;
                    continue;
                }
            }
            predecessor = target;
            target = next;
        }
    }
    ...
    return handled;
    }
}

小结:

我们总结一下:

上一篇 下一篇

猜你喜欢

热点阅读