事件分发 - 阅读源码、查漏补缺

View的事件处理:
dispatchTouchEvent -> onTouchEvent -> performClick -> 如果设置了setOnClickListener,那么此时就会调用。

注意:如果View设置了setOnTouchListener,并且在回调方法onTouch里面return true,那么View的onTouchevent方法就不会执行,当然setOnClickListener的回调就更不会执行了。

//noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

            if (!result && onTouchEvent(event)) {
                result = true;
            }


ViewGroup的事件处理:
dispatchTouchEvent -> dispatchTransformedTouchEvent -> super.dispatchTouchEvent or child.dispatchTouchEvent

注意:mFirstTouchTarget这个参数非常的重要,
1.在事件ACTION_DOWN、ACTION_POINTER_DOWN、ACTION_HOVER_MOVE中,遍历子View,调用dispatchTransformedTouchEvent -> child.dispatchTouchEvent -> child.onTouchEvent,如果返回true,那么就会将子View通过addTouchTarget加入到mFirstTouchTarget链表的头部。

if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                                // Child wants to receive touch within its bounds.
                                mLastTouchDownTime = ev.getDownTime();
                                if (preorderedList != null) {
                                    // childIndex points into presorted list, find original index
                                    for (int j = 0; j < childrenCount; j++) {
                                        if (children[childIndex] == mChildren[j]) {
                                            mLastTouchDownIndex = j;
                                            break;
                                        }
                                    }
                                } else {
                                    mLastTouchDownIndex = childIndex;
                                }
                                mLastTouchDownX = ev.getX();
                                mLastTouchDownY = ev.getY();
                                newTouchTarget = addTouchTarget(child, idBitsToAssign);
                                alreadyDispatchedToNewTouchTarget = true;
                                break;
                            }

2.其他事件,就会去判断mFirstTouchTarget是否为null,如果为null,则后续调用super.dispatchTouchEvent;如果不为null,则依次遍历mFirstTouchTarget,分别调用mFirstTouchTarget.child.dispatchTouchEvent。

// 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 {
//这里的intercepted会受onInterceptTouchEvent方法的返回值影响,一旦intercepted为true,将会把mFirstTouchTarget全部清除,并且对所有的target.child发送ACTION_CANCEL事件
                        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;
                }
            }

这里需要注意的是如果onInterceptTouchEvent返回为true,那么会给mFirstTouchTarget中所有的View分发ACTION_CANCEL事件,并且将mFirstTouchTarget中所有的Target全部移除掉,因此如果一个事件序列如果onInterceptTouchEvent返回为true,那么后续事件都不会分发给子View了,除非有一个新的事件ACTION_POINTER_DOWN的到来。

多点触控:
注意:一个View里面只能收到一次ACTION_DOWN事件,多次ACTION_POINTER_DOWN事件。但是如果是ViewGroup接受到ACTION_POINTER_DOWN事件,且第二个手指与第一个手指处于不同的两个View,那么会调用MotionEvent.split方法将ACTION_POINTER_DOWN变成ACTION_DOWN事件,传递给新的touchTarget.child中,因此在ViewGroup看来是接收到了一次ACTION_DOWN事件,但是不同的两个View分别接收到了一次ACTION_DOWN事件,总计为2次。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值