android 事件分发机制 概念理解

android 事件分发机制

参考资料

Android 事件分发机制源码和实例解析

Android View 事件分发机制详解

图解 Android 事件分发机制

图解View的事件分发机制

原理

  1. 分发事件 的起始点:

从 Activity 开始,Activity 源码

Activity 有两个方法 dispatchTouchEvent 和 onTouchEvent

Activity—dispatchTouchEvent

    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

    getWindow().superDispathTouchEvent 就是用来分发事件到
    DecorView 中。如果整个 ViewTree 没有消费事件,会调用
    Activity 的 onTouchEvent。

源码中: 
  protected void onUserLeaveHint() {
    }

Activity—onTouchEvent

    public boolean onTouchEvent(MotionEvent event) {
        if (mWindow.shouldCloseOnTouch(this, event)) {
            finish();
            return true;
        }

        return false;
    }
  1. 分发事件 的终点 也是 Activity 从源码可知

应为 分发的方法是 acticity 自己定义的方法
dispatchTouchEvent,所有最后只有他自己来处理该事件。

  1. 分发事件的过程

主要涉及 View 和 ViewGroup (在 xml 中 设置)

View 只有 onTouchEvent 和 dispatchTouchEvent 两个方法。

ViewGroup 有 onTouchEvent / dispatchTouchEvent 和 onInterceptTouchEvent 三个方法。

图片案例

  1. 注意事项:

View 或 ViewGroup 有两个核心的行为:拦截(intercept) 和 消费(consume)。这两者是相互独立的,拦截不一定消费。是否要拦截看 onIntercepTouchEvent。是否要消费看 onTouchEvent。

  1. 方法理解
dispatchTouchEvent,该方法封装了事件分发的整个过程。是事
件分发的 调度者 和 指挥官 。的核心过程均在该方法中。下面的
onInterceptTouchEvent 和 onTouchEvent
的回调的调用就在该方法体中。是否传递事件到
onInterceptTouchEvent 和 onTouchEvent 由
dispatchTouchEvent 决定。
onInterceptTouchEvent,该方法决定了是否拦截事件。只有
ViewGroup 有该回调。返回 true 表示拦截,返回 false
表示不拦截。自定义 View
的时候,可以重载该方法,通过一些特定的逻辑来决定是否拦截
事件。如果拦截,接下来会调用该 ViewGroup 的 onTouchEvent
来处理事件。
onTouchEvent,该方法处理了事件,并决定是否继续消费后续
事件。该方法调用的前置条件:

该 View 拦截了事件
子 View 都不消费事件
没有子 View


该方法正式处理 MotionEvent。返回 true 表示消费,返回
false 不消费。如果消费,接下来的事件还会传递到该 View 的
dispatchTouchEvent 中;如果不消费,后面的事件不会再传过来。

onTouchListener 的 onTouch 回调,和 onTouchEvent
一样,优先级比 onTouchEvent 高,如果有设置该监听,并且
onTouch 返回 true,就不会再调用 onTouchEvent 了。如果返回
false,事件还是会传递到 onTouchEvent 中。
dispatchTransformedTouchEvent 关键部分

// Perform any necessary transformations and dispatch.
if (child == null) {
    handled = super.dispatchTouchEvent(transformedEvent);
} else {
    final float offsetX = mScrollX - child.mLeft;
    final float offsetY = mScrollY - child.mTop;
    transformedEvent.offsetLocation(offsetX, offsetY);
    if (! child.hasIdentityMatrix()) {
        transformedEvent.transform(child.getInverseMatrix());
    }

    handled = child.dispatchTouchEvent(transformedEvent);
}

也就是 dispatchTransformTouchEvent 完成了分发的最后过程:

a. 传入的 child 不为空,转化坐标为 child 的坐标系,调用
child.dispatchTouchEvent 向 child 分发事件
b. 传入的 child 为空,调用 super.dispatchTouchEvent
分发事件到 onTouchEvent 中

  1. 特殊情况 子 View –requestDisallowInterceptTouchEvent
比较特殊的情况有,子 View 可以使用 requestDisallowInterceptTouchEvent 影响去父 View
的分发,可以决定父 View 是否要调用 onInterceptTouchEvent
。比如,requestDisallowInterceptTouchEvent(true),父 View
就不用调用 onInterceptTouchEvent
来判断拦截,而就是不拦截。

该方法可以用来解决手势冲突。比如子 View
先消费了事件,但是后面父 View
也满足了手势触发的条件而拦截事件,导致子 View
手势执行一半后无法继续响应。可以使用
requestDisallowInterceptTouchEvent(true),这样后面的事
件,父 View 不会走 onInterceptTouchEvent
回调来判断是否要拦截事件,而是直接把事件继续传下来。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值