android 事件分发机制 概念理解

来源:互联网 发布:舍伍德算法理解 编辑:程序博客网 时间:2024/05/29 14:15

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 0
原创粉丝点击