zoukankan      html  css  js  c++  java
  • Android view 的事件分发机制

    1 事件的传递顺序是 Activity -> Window -> 顶层View

    touch 事件产生后,最先由 activity 的 dispatchTouchEvent 处理

      /**
         * Called to process touch screen events.  You can override this to
         * intercept all touch screen events before they are dispatched to the
         * window.  Be sure to call this implementation for touch screen events
         * that should be handled normally.
         *
         * @param ev The touch screen event.
         *
         * @return boolean Return true if this event was consumed.
         */
        public boolean dispatchTouchEvent(MotionEvent ev) {
            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
                onUserInteraction();
            }
            if (getWindow().superDispatchTouchEvent(ev)) {
                return true;
            }
            return onTouchEvent(ev);
        }

    接着事件会传到 Window 的 superDispatchTouchEvent。 如果所有的 view 都没有消费事件,最后会交给 activity 的 onTouchEvent 处理。

    2 Window 是一个抽象类,它的唯一实现类是 PhoneWindow

    /**
     * Abstract base class for a top-level window look and behavior policy.  An
     * instance of this class should be used as the top-level view added to the
     * window manager. It provides standard UI policies such as a background, title
     * area, default key processing, etc.
     *
     * <p>The only existing implementation of this abstract class is
     * android.view.PhoneWindow, which you should instantiate when needing a
     * Window.
     */
    public abstract class Window {
    }

    查看 PhoneWindow 的 superDispatchTouchEvent

    public boolean superDispatchTouchEvent(MotionEvent event) {        
        return mDecor.superDispatchTouchEvent(event);    
    }

    调用了 mDecor 的 superDispatchTouchEvent

    private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {}
    
    // This is the top-level view of the window, containing the window decor.
    private DecorView mDecor;

    mDecor 就是 DecorView, DecorView 是一个 FrameLayout, 就是我们 setContentView 所设置 view 的父容器。

    继续看 DecorView 的superDispatchTouchEvent

    public boolean superDispatchTouchEvent(MotionEvent event) {
        return super.dispatchTouchEvent(event);
    }

    调用了父类的 dispatchTouchEvent,  FrameLayout 中没有 dispatchTouchEvent, 实际上调用了 FrameLayout 的父类 ViewGroup 的 dispatchTouchEvent。

    到此事件就传递到了顶层View(ViewGroup) 中,接着事件就从顶层 view 开始向子view分发。

    3 事件分发主要涉及 3 个方法

    public boolean dispatchTouchEvent(MotionEvent event)

    事件传递到一个 view 时就会先调用这个 view 的 dispatchTouchEvent 进行往下分发

    public boolean onInterceptTouchEvent(MotionEvent ev)

    进行事件的拦截,只有 ViewGroup 有拦截方法, 单一View没有,事件传到 单一View 就直接调用 onTouchEvent 进行处理了

    public boolean onTouchEvent(MotionEvent event)

    处理事件,true 表示消费这个事件, false 表示不消费

    下面的伪代码可以很好的说明事件的分发过程

    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean consume = false;
        if (onInterceptTouchEvent(ev)) {
            consume = onTouchEvent(ev);
        }else {
            consume = child.dispatchTouchEvent(ev);
        }
        
        return consume;
    }

    事件传递到顶层 ViewGroup 中后, 就会调用 ViewGroup dispatchTouchEvent 进行分发。如果这个 ViewGroup 的 onInterceptTouchEvent 返回 true 表示它要拦截这个事件,接着就会调用它的 onTouchEvent 进行处理。如果不拦截则会交给它的子 view 继续进行分发, 如此反复直到事件被最终处理。

    正常情况下,一个事件序列只能被一个 view 拦截且消耗。一个 view 一旦拦截了某个事件,那么同一个事件序列内的所有的事件都会交给它处理。

    如果一个 view 的 onTouchEvent 返回 false, 那么它的父容器的 onTouchEvent 将会被调用,依次类推。如果所有的 view 都不处理这个事件,这个事件最后会返回到 activity 的 onTouchEvent 进行处理。

    事件分发具体细节较为复杂,但基本流程就是上面的伪代码。事件分发机制是处理滑动冲突的根本,知道了原理,遇到问题再多看看源码就行了。

      

  • 相关阅读:
    MicroPython的开发板
    python 安装mysql报错
    30个mysql千万级大数据SQL查询优化技巧详解
    PHP针对数字的加密解密类,可直接使用
    form表单公用
    生成随机邀请码
    Tp5自动验证
    protected和private的区别
    中国俗语大全
    更改Unity项目新建模板
  • 原文地址:https://www.cnblogs.com/lesliefang/p/5274261.html
Copyright © 2011-2022 走看看