Android O: 触摸事件传递流程源码分析(下)

前一篇博客中,我们分析了ViewGroup传递触摸事件的流程,详见:
Android O: 触摸事件传递流程源码分析(上)

本篇博客,我们主要来看一下View传递触摸事件的流程。


ViewGroup在分发事件时,会调用dispatchTransformedTouchEvent方法,
将MotionEvent分发给合适的Child View或ViewGroup。
对于Child View而言,dispatchTransformedTouchEvent函数,
最终还是会调用View的dispatchTouchEvent方法。

现在我们就来看看View的dispatchTouchEvent方法:

public boolean dispatchTouchEvent(MotionEvent event) {
    // If the event should be handled by accessibility focus first.
    if (event.isTargetAccessibilityFocus()) {
        // We don't have focus or no virtual descendant has it, do not handle the event.
        if (!isAccessibilityFocusedViewOrHost()) {
            return false;
        }

        // We have focus and got the event, then use normal event dispatch.
        event.setTargetAccessibilityFocus(false);
    }
    ............

从上面的代码可以看出,与ViewGroup处理MotionEvent的过程一致,
View也会先针对Accessibility Focus事件进行处理。

如果事件要求Accessibility Focus,但当前View不具备这种能力,
那么分发结束,直接返回false;
如果当前View具有Accessibility Focus能力,那么收到这种类型的事件后,
直接将MotionEvent对应的Flag置为false。


我们继续跟进代码:

//用于保存最终的结果,记录事件是否被当前View消费掉
boolean result = false;

//这部分应该和测试相关
if (mInputEventConsistencyVerifier != null) {
    mInputEventConsistencyVerifier.onTouchEvent(event, 0);
}

//收到新开始的事件,清除旧有的记录信息
final int actionMasked = event.getActionMasked();
if (actionMasked == MotionEvent.ACTION_DOWN) {
    // Defensive cleanup for new gesture
    stopNestedScroll();
}

//与ViewGroup一样,需要进行安全性检测,避免View被恶意程序覆盖
if (onFilterTouchEventForSecurity(event)) {
    //从注释来看,此处处理鼠标相关的输入,不用特意关注
    if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
        result = true;
    }

    //View存在onTouchListener时,onTouchListener优先消费
    ListenerInfo li = mListenerInfo;
    if (li != null && li.mOnTouchListener != null
            && (mViewFlags & ENABLED_MASK) == ENABLED
            && li.mOnTouchListener.onTouch(this, event)) {
        result = true;
    }

    //然后才是View调用onTouchEvent消费事件
    //View的onTouchEvent函数,会根据事件的类型进行相应的处理
    if (!result && onTouchEvent(event)) {
        result = true;
    }
}

//仍然是测试相关
if (!result && mInputEventConsistencyVerifier != null) {
    mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
}

// Clean up after nested scrolls if this is the end of a gesture;
// also cancel it if we tried an ACTION_DOWN but we didn't want the rest
// of the gesture.
// 事件处理完毕或ACTION_DOWN未处理, 清楚记录
if (actionMasked == MotionEvent.ACTION_UP ||
        actionMasked == MotionEvent.ACTION_CANCEL ||
        (actionMasked == MotionEvent.ACTION_DOWN && !result)) {
    stopNestedScroll();
}

return result;

至此,View的事件分发流程分析完毕。
可以看出,由于View不需要继续将事件分发给Child View,
因此它需要管理的状态较少,事件处理的逻辑也比ViewGroup简单。

大致上来说,View处理事件的主要逻辑如下图所示:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值