返回

AndroidViewGroup事件分发机制与dispatchTouchEvent源码剖析

Android

导论

Android的事件分发机制是应用程序响应用户输入的基础。理解这一机制对于开发高质量的Android应用程序至关重要。本文将深入分析Android ViewGroup的事件分发机制,重点剖析dispatchTouchEvent源码,以便更好地理解Android事件处理的原理。

ViewGroup的事件分发机制

ViewGroup是Android应用程序中布局的基础组件。它负责管理其子视图的布局和显示,并处理触摸事件和其他输入事件。ViewGroup的事件分发机制主要由dispatchTouchEvent方法实现。

dispatchTouchEvent方法

dispatchTouchEvent方法是ViewGroup处理触摸事件的入口。当触摸事件发生时,系统会调用该方法,并传递触摸事件对象作为参数。该方法首先调用onUserInteraction()方法,然后循环遍历子视图,并调用子视图的dispatchTouchEvent方法。如果子视图处理了触摸事件,则该方法返回true,否则返回false。

public boolean dispatchTouchEvent(MotionEvent ev) {
    onUserInteraction();
    boolean handled = false;
    if (mFirstTouchTime == -1) {
        long now = SystemClock.uptimeMillis();
        mFirstTouchTime = now;
        mLastTouchTime = now;
    }
    ...
    for (int i = 0; i < mChildrenCount; i++) {
        final View child = mChildren[i];
        if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
                && child.getAlpha() > 0.5f && child.isTouchEventEnabled()) {
            if (!child.isDuplicateParentStateEnabled()) {
                child.dispatchTouchEvent(ev);
            } else if (ev.getActionMasked() != MotionEvent.ACTION_CANCEL) {
                final float x = ev.getX();
                final float y = ev.getY();
                child.mLeft = (int) x;
                child.mTop = (int) y;
                child.mRight = (int) (x + child.getMeasuredWidth());
                child.mBottom = (int) (y + child.getMeasuredHeight());
                child.dispatchTouchEvent(ev);
            }
            handled = true;
        }
    }
    ...
    mLastTouchTime = SystemClock.uptimeMillis();
    return handled;
}

onUserInteraction()方法

onUserInteraction()方法是一个空方法,在dispatchTouchEvent方法中被调用。该方法用于重置用户的触摸超时时间,防止用户在长时间不触摸屏幕后被注销。

DecorView

DecorView是Activity的根视图。它继承了FrameLayout,并负责管理Activity的窗口内容。DecorView的dispatchTouchEvent方法会将触摸事件传递给Activity的根布局。

源码分析

public boolean dispatchTouchEvent(MotionEvent ev) {
    onUserInteraction();
    boolean handled = false;
    if (mFirstTouchTime == -1) {
        long now = SystemClock.uptimeMillis();
        mFirstTouchTime = now;
        mLastTouchTime = now;
    }
    ...
    for (int i = 0; i < mChildrenCount; i++) {
        final View child = mChildren[i];
        if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
                && child.getAlpha() > 0.5f && child.isTouchEventEnabled()) {
            if (!child.isDuplicateParentStateEnabled()) {
                child.dispatchTouchEvent(ev);
            } else if (ev.getActionMasked() != MotionEvent.ACTION_CANCEL) {
                final float x = ev.getX();
                final float y = ev.getY();
                child.mLeft = (int) x;
                child.mTop = (int) y;
                child.mRight = (int) (x + child.getMeasuredWidth());
                child.mBottom = (int) (y + child.getMeasuredHeight());
                child.dispatchTouchEvent(ev);
            }
            handled = true;
        }
    }
    ...
    mLastTouchTime = SystemClock.uptimeMillis();
    return handled;
}

代码解析

dispatchTouchEvent方法首先调用onUserInteraction()方法,然后循环遍历子视图,并调用子视图的dispatchTouchEvent方法。如果子视图处理了触摸事件,则该方法返回true,否则返回false。

在循环中,该方法首先检查子视图是否可见、是否透明以及是否启用了触摸事件。如果子视图满足这些条件,则该方法会调用子视图的dispatchTouchEvent方法。如果子视图是DuplicateParentStateEnabled,则该方法会将子视图的边界设置为触摸事件的坐标,然后调用子视图的dispatchTouchEvent方法。

总结

通过对dispatchTouchEvent方法的分析,我们了解了Android ViewGroup的事件分发机制。该机制主要通过循环遍历子视图,并调用子视图的dispatchTouchEvent方法来实现。如果子视图处理了触摸事件,则该方法返回true,否则返回false。

希望本文对您理解Android ViewGroup的事件分发机制有所帮助。如果您有任何问题或建议,欢迎随时与我联系。