Android onTouchEvent和onClick沖突、performClick()源碼分析

我們在開發(fā)中往往會對一個View或者ViewGroup進行自定義的操作,比如重寫她的onTouchEvent事件

    @Override
    public boolean onTouchEvent(@NonNull MotionEvent event) {
        return super.onTouchEvent(event);
    }

該函數是有個返回值的,那么FALSE和TRUE代表什么意思呢?

true:代表事件被截斷,事件被該函數消耗了。
false:事件不被截斷,可以繼續(xù)分發(fā)到下一步

點擊事件的分發(fā)順序是:
dispatchTouchEvent()—>onTouch(),OnTouchListener接口—>onTouchEvent()—>onClick()


image.png

以上是View分發(fā)的原理。
之所以這就可以理解了如果我們僅是重寫了onTouchEvent,onClick事件事件一定不會觸發(fā),是因為我們在onTouchEvent函數中返回了true,onClick事件接收不到事件了.

@Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                break;
            case MotionEvent.ACTION_CANCEL:
                break;
            default:
                break;
        }
        return true;
    }

(1)MotionEvent.ACTION_DOWN 按下View,是所有事件的開始
(2)MotionEvent.ACTION_MOVE 滑動事件
(3)MotionEvent.ACTION_UP 與down對應,表示抬起
那么我們只需在up事件判斷當前的手勢是否是點擊事件,方法可能會有多種,我在這邊提供一個最簡單的辦法來實現,判斷down事件相較于up事件的偏移量,如下代碼

  @Override
    public boolean onTouchEvent(MotionEvent event) {
        float fromX = 0;
        float fromY=0;
        boolean action=true;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                fromX=event.getX();
                fromY=event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                float dx=event.getX();
                float dy=event.getY();
                if (Math.abs(dx-fromX)<3&&Math.abs(dy-fromY)<3) {
                    action=false;
                }
                break;
            case MotionEvent.ACTION_CANCEL:
                break;
            default:
                break;
        }
        return action;
    }

小伙伴們是不是認為這樣就可以解決了!!!,如果這么簡單的話,那我還專門寫個博客干啥子。。。網上用此方法解決問題的文章多的要死,但90%都是有問題的,雖然我們成功下發(fā)了事件到onClick,但是onClick事件并沒有執(zhí)行, 所以我們還得在條件判斷內加一句主動調點擊事件的代碼:

this.performClick();

我們來分析一下這個函數的源碼:

    public boolean performClick() {
        final boolean result;
        final ListenerInfo li = mListenerInfo;
        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事件,則通過此方法主動調用onClikck函數。其中的mListenerInfo對象即是是否注冊了監(jiān)聽事件:

view.setOnClickListener(this);

好了,今天的文章就到這里了,有什么問題可以給我留言,good job:)

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容