【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 三 )(一)

文章目录

Android 事件分发 系列文章目录

前言

一、获取子组件

二、当前遍历的子组件的事件分发

三、ViewGroup 事件分发相关源码

前言

接上一篇博客 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 二 ) , 继续分析 ViewGroup 的事件分发机制后续代码 ;






一、获取子组件


之前已经按照 Z 轴深度 , 将组件进行排序 , 放在集合中 ;


倒序遍历排列好的组件 , 按照 Z 轴的上下顺序 , 先遍历的 Z 轴方向上 , 放在最上面的组件 , 也就是顶层组件 ;


for (int i = childrenCount - 1; i >= 0; i--) {


先获取组件索引 , 然后获取索引对应的子组件 ;


                       

// 获取索引
                            final int childIndex = getAndVerifyPreorderedIndex(
                                    childrenCount, i, customOrder);
                            // 获取索引对应组件 
                            final View child = getAndVerifyPreorderedView(
                                    preorderedList, children, childIndex);


然后判定组件是否符合要求 :

调用 canViewReceivePointerEvents 方法 , 判定组件是否可见 , 会否处于动画中 ;


/**
     * Returns true if a child view can receive pointer events.
     * 判定控件是否可见 / 是否处于动画中 
     * @hide
     */
    private static boolean canViewReceivePointerEvents(@NonNull View child) {
        return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
                || child.getAnimation() != null;
    }


调用 isTransformedTouchPointInView 判定手指是否在控件上面 ;


 

/**
     * Returns true if a child view contains the specified point when transformed
     * into its coordinate space.
     * Child must not be null.
     * 判定手指是否触摸到了组件 , 是否在组件区域范围内 
     * @hide
     */
    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;
    }


如果上面 3 33 个条件只要存在 1 11 个不满足 , 则不传递触摸事件 , 在遍历时直接 continue , 越过该控件 , 遍历下一个控件 ;


   

// X 控件范围 A , 如果手指按在 B 范围 , 不会触发 X 控件的事件 
        // 判定当前的组件是否可见 , 是否处于动画过程中 
        // ① canViewReceivePointerEvents 判定组件是否可见 , 会否处于动画 
        // ② isTransformedTouchPointInView 判定手指是否在控件上面 ; 
        // 上述两种情况 , 不触发事件 
                            if (!canViewReceivePointerEvents(child)
                                    || !isTransformedTouchPointInView(x, y, child, null)) {
                                ev.setTargetAccessibilityFocus(false);
                                // 不触发事件 
                                continue;
                            }



ViewGroup | dispatchTouchEvent 方法相关源码 :


@UiThread
public abstract class ViewGroup extends View implements ViewParent, ViewManager {
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
  ...
      // 倒序遍历 按照 Z 轴的上下顺序 , 排列好的组件 
      // 先遍历的 Z 轴方向上 , 放在最上面的组件 , 也就是顶层组件 
                        for (int i = childrenCount - 1; i >= 0; i--) {
                            // 获取索引
                            final int childIndex = getAndVerifyPreorderedIndex(
                                    childrenCount, i, customOrder);
                            // 获取索引对应组件 
                            final View child = getAndVerifyPreorderedView(
                                    preorderedList, children, childIndex);
                            // If there is a view that has accessibility focus we want it
                            // to get the event first and if not handled we will perform a
                            // normal dispatch. We may do a double iteration but this is
                            // safer given the timeframe.
                            // 无障碍 辅助功能 
                            if (childWithAccessibilityFocus != null) {
                                if (childWithAccessibilityFocus != child) {
                                    continue;
                                }
                                childWithAccessibilityFocus = null;
                                i = childrenCount - 1;
                            }
        // X 控件范围 A , 如果手指按在 B 范围 , 不会触发 X 控件的事件 
        // 判定当前的组件是否可见 , 是否处于动画过程中 
        // ① canViewReceivePointerEvents 判定组件是否可见 , 会否处于动画 
        // ② isTransformedTouchPointInView 判定手指是否在控件上面 ; 
        // 上述两种情况 , 不触发事件 
                            if (!canViewReceivePointerEvents(child)
                                    || !isTransformedTouchPointInView(x, y, child, null)) {
                                ev.setTargetAccessibilityFocus(false);
                                // 不触发事件 
                                continue;
                            }
        
        // 截止到此处 , 可以获取子组件进行操作   
  ...
    }
    /**
     * Returns true if a child view can receive pointer events.
     * 判定控件是否可见 / 是否处于动画中 
     * @hide
     */
    private static boolean canViewReceivePointerEvents(@NonNull View child) {
        return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
                || child.getAnimation() != null;
    }
    /**
     * Returns true if a child view contains the specified point when transformed
     * into its coordinate space.
     * Child must not be null.
     * 判定手指是否触摸到了组件 , 是否在组件区域范围内 
     * @hide
     */
    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;
    }
}



源码路径 : /frameworks/base/core/java/android/view/ViewGroup.java



上一篇:EF Core中使用事务及分布式事务(官方文档)


下一篇:[PAT][Basic level]1095