Android事件分发机制(3)

1. 如果一个布局有两个按钮重合了点击按钮为什么只有一个点击到,先点击到哪个?

 之前分析过事件右Activity分发到ViewGroup再分发到view,那么看一下ViewGroup的分发方法
@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
		//.....下面是主要代码
		if (newTouchTarget == null && childrenCount != 0) {
                        final float x = ev.getX(actionIndex);
                        final float y = ev.getY(actionIndex);
                        // Find a child that can receive the event.查找可以接受event的view
                        // Scan children from front to back. 扫描view从上到下
                        // 为view排序的方法接下来进入此方法看一下
                        final ArrayList<View> preorderedList = buildTouchDispatchChildList();
                        final boolean customOrder = preorderedList == null
                                && isChildrenDrawingOrderEnabled();
                        final View[] children = mChildren;
                        for (int i = childrenCount - 1; i >= 0; i--) {
                            final int childIndex = getAndVerifyPreorderedIndex(
                                    childrenCount, i, customOrder);
                            final View child = getAndVerifyPreorderedView(
                                    preorderedList, children, childIndex);
		//.....
	}

为view排序的集合

ArrayList<View> buildOrderedChildList() {
        final int childrenCount = mChildrenCount;
        if (childrenCount <= 1 || !hasChildWithZ()) return null;

        if (mPreSortedChildren == null) {
            mPreSortedChildren = new ArrayList<>(childrenCount);
        } else {
            // callers should clear, so clear shouldn't be necessary, but for safety...
            mPreSortedChildren.clear();
            mPreSortedChildren.ensureCapacity(childrenCount);
        }

        final boolean customOrder = isChildrenDrawingOrderEnabled();
        for (int i = 0; i < childrenCount; i++) {
            // add next child (in child order) to end of list
            final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
            final View nextChild = mChildren[childIndex];
            final float currentZ = nextChild.getZ();

            // insert ahead of any Views with greater Z
            int insertIndex = i;
            while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) {
                insertIndex--;
            }
            mPreSortedChildren.add(insertIndex, nextChild);
        }
        return mPreSortedChildren;
    }

经过排序,ViewGroup事件会先分配到上层view然后再一次传递直到事件被消费终止。

2. 什么情况view可以接收事件(什么情况view不会消费事件)
在ViewGroup的dispatchTouchEvent方法里面有这样一个判断

if (!canViewReceivePointerEvents(child)
                                    || !isTransformedTouchPointInView(x, y, child, null)) {
                                ev.setTargetAccessibilityFocus(false);
                                continue;
                            }

这三点必须都满足才当前view才不会被continue掉进行下一个循环
第一个!canViewReceivePointerEvents(child)。和VISIBLE状态和currentAnimation有关

private static boolean canViewReceivePointerEvents(@NonNull View child) {
        return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
                || child.getAnimation() != null;
    }

第二个方法isTransformedTouchPointInView 手指的位置必须点击到了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;
    }

第三个··········

/** @hide */
    public final void setTargetAccessibilityFocus(boolean targetsFocus) {
        final int flags = getFlags();
        nativeSetFlags(mNativePtr, targetsFocus
                ? flags | FLAG_TARGET_ACCESSIBILITY_FOCUS
                : flags & ~FLAG_TARGET_ACCESSIBILITY_FOCUS);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值