事件分发(一)(onTouch和onClick的执行)

286 阅读2分钟

首先看一下中重要的源码

public boolean dispatchTouchEvent(MotionEvent event) {
        ......
        boolean result = false;
        ......
        //过滤onTouchEvent事件是否安全,正常流程都会返回 true
        if (onFilterTouchEventForSecurity(event)) {
            ......
            //首先判断是否设置了onTouchListener,如果设置了首先执行onTouch方法
            //ListenerInfo是在我们设置setOnTouchListener时初始化的
            //可以看下setOnTouchListener,其中的getListenerInfo是单例模式
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null//已经设置了不会空
                    && (mViewFlags & ENABLED_MASK) == ENABLED//判断按钮是否能够点击
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;//result和 onTouch 的返回值保持一致
            }
            //只有onTouch方法返回为 false 的情况下才会去执行 onTouchEvent
            //onTouchEvent中会去执行 onClick 方法
            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }
        ......
        return result;
    }

从上面的代码可以看出 onTouchListener 的优先级高于 onTouchEvent,只有当 onTouch 方法

返回为 false 的情况下才会去执行 onTouchEvent,再来看一下 onTouchEvent 的部分重要源码

public boolean onTouchEvent(MotionEvent event) {
        final float x = event.getX();
        final float y = event.getY();
        final int viewFlags = mViewFlags;
        final int action = event.getAction();
        ......
        if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
            switch (action) {
                //会在ACTION_UP事件中处理onClick
                //也就是在我们手指松手的那一刻才会去执行 onClick 方法
                case MotionEvent.ACTION_UP:
                    mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
                    if ((viewFlags & TOOLTIP) == TOOLTIP) {
                        handleTooltipUp();
                    }
                    ......
                    if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
                        ......
                        if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
                            // This is a tap, so remove the longpress check
                            removeLongPressCallback();

                            // Only perform take click actions if we were in the pressed state
                            if (!focusTaken) {
                                // Use a Runnable and post this rather than calling
                                // performClick directly. This lets other visual state
                                // of the view update before click actions start.
                                if (mPerformClick == null) {
                                    mPerformClick = new PerformClick();
                                }
                                if (!post(mPerformClick)) {
                                    //该方法最终会去执行 onClick 方法
                                    performClickInternal();
                                }
                            }
                        }
                    ......
                    mIgnoreNextUpEvent = false;
                    break;
private boolean performClickInternal() {
        ......
        return performClick();
 }
 public boolean performClick() {
        ......
        final boolean result;
        final ListenerInfo li = mListenerInfo;
        //关键代码,判断是否设置了onClickListener,这块和onTouch时类似
        if (li != null && li.mOnClickListener != null) {
            playSoundEffect(SoundEffectConstants.CLICK);
            li.mOnClickListener.onClick(this);
            result = true;
        } else {
            result = false;
        }
        ......
        return result;//最终返回执行结果
  }

下面来一张onTouch方法和onClick方法执行的流程图


源码相关应用:

场景:通过以上源码的分析,我们知道如果一个View同时设置了onTouchListener和

onClickListener,此时要想onClick得到执行我们必须在onTouch方法中手动返回false

如果业务需求我们即要onTouch方法最终返回true,同时又要onClick得到执行

根据上边的源码我们可以在onTouch方法中手动执行 v.performClick

好,这篇学习笔记结束啦