美文网首页
2018-12-28View 的事件分发

2018-12-28View 的事件分发

作者: 猫KK | 来源:发表于2018-12-28 11:49 被阅读0次

注意,这里分析的是view 的事件分发,不是ViewGroup

相比ViewGroup 的事件分发,view的事件分发只有两个方法,相对简单

 @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.e("TAG", "view dispatchTouchEvent: ----->" + event.getAction());
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("TAG", "view onTouchEvent: ----->" + event.getAction());
        return super.onTouchEvent(event);
    }

dispatchTouchEvent 方法用于分发,onTouchEvent 用于处理,先来看第一个方法

public boolean dispatchTouchEvent(MotionEvent event) {
    //  省略代码......
    if (onFilterTouchEventForSecurity(event)) {
            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                result = true;
            }
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            //判断是否注册onTouch 事件,从这里可以知道,先调用的必然是onTouch 
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }
            //根据onTouch 的返回来判断是否调用onTouchEvent 方法
            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }  
     //省略代码.......
    return result;
}

通过上面的代码能知道view 注册事件的调用顺序,当view设置了onTouch 会首先调用,当onTouch 返回ture 时不会再调用onTouchEvent

//通过setOnTouchListener 的方式注册onTouch事件
view.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e("TAG", "onTouch: ----> 1" );
                //当返回true 时 onTouchEvent 方法将不会调用
                return true;
            }
        });

接下来分析 onTouchEvent 方法,假设这时 onTouch 返回false

public boolean onTouchEvent(MotionEvent event) {
    //  获取当前点击的位置
    final float x = event.getX();
    final float y = event.getY();
    final int viewFlags = mViewFlags;
    final int action = event.getAction();
    //省略代码..........
    switch (action) {
        // 在ACTION_UP 事件中触发 onClick 事件
        case MotionEvent.ACTION_UP:
                if (mPerformClick == null) {
                       mPerformClick = new PerformClick();
                }
                 if (!post(mPerformClick)) {
                       performClickInternal();
                }
}

 private boolean performClickInternal() {
        // Must notify autofill manager before performing the click actions to avoid scenarios where
        // the app has a click listener that changes the state of views the autofill service might
        // be interested on.
        notifyAutofillManagerOnClick();

        return performClick();
    }

 public boolean performClick() {
        // We still need to call this method to handle the cases where performClick() was called
        // externally, instead of through performClickInternal()
        notifyAutofillManagerOnClick();

        final boolean result;
        final ListenerInfo li = mListenerInfo;
        //如果设置监听了,调用,并返回 true
        if (li != null && li.mOnClickListener != null) {
            playSoundEffect(SoundEffectConstants.CLICK);
            li.mOnClickListener.onClick(this);
            result = true;
        } else {
            result = false;
        }

        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);

        notifyEnterOrExitForAutoFillIfNeeded(true);

        return result;
    }

通过上面可以知道,view 的onClick 事件是在onTouchEvent 中 ACTION_UP 执行的,所以只有抬手后才会执行onClick。所以view 的事件执行顺序为:dispatchTouchEvent -> onTouch -> onTouchEvent -> onClick。所以当 onTouch 返回ture 是 onClick 事件将不会执行。最后来看下面这种情况,当继承view 重写 dispatchTouchEvent 直接返回ture

 @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.e("TAG", "view dispatchTouchEvent: ----->" + event.getAction());
        return ture;
    }

当直接在 dispatchTouchEvent 中返回 ture 那执行循序是怎么样的呢?
答案是只执行 dispatchTouchEvent 因为没有调用父类view 中的 dispatchTouchEvent 方法所以后续的方法都不会执行,如果又想执行后续方法又想返回ture 呢?可以如下

 @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.e("TAG", "view dispatchTouchEvent: ----->" + event.getAction());
        //手动调用view 中的 dispatchTouchEvent
        super.dispatchTouchEvent(event);
        return ture;
    }

总结:view 的事件分发相对简单,正常执行顺序为:dispatchTouchEvent -> onTouch -> onTouchEvent -> onClick 可以根据需求在不同的地方返回 ture 可以让后续的方法不在执行

相关文章

网友评论

      本文标题:2018-12-28View 的事件分发

      本文链接:https://www.haomeiwen.com/subject/szrslqtx.html