Button的ontouch,onclick,onLongclick的執行順序

Android中,onClickonLongClick的觸發是和ACTION_DOWNACTION_UP相關的,在時序上,如果我們在一個View中同時覆寫了onClickonLongClickonTouchEvent的話,onTouchEvent是最先捕捉到ACTION_DOWNACTION_UP事件的,其次纔可能觸發onClick或者onLongClick。主要的邏輯在View.java中的onTouchEvent方法中實現的:

<span style="font-size:14px;"><span style="color:#333333;">case MotionEvent.ACTION_DOWN:
    mPrivateFlags |= PRESSED;
    refreshDrawableState();
    if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) {
        </span><span style="color:#ff0000;"> postCheckForLongClick(); </span><span style="color:#333333;">
    }
    break;</span></span>
<span style="font-size:14px;"><span style="color: rgb(51, 51, 51);">
case MotionEvent.ACTION_UP:
    if ((mPrivateFlags & PRESSED) != 0) {
         boolean focusTaken = false;
         if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
               focusTaken = requestFocus();
         }
    if (!mHasPerformedLongPress) {
       if (mPendingCheckForLongPress != null) {
             removeCallbacks(mPendingCheckForLongPress);
       }
       if (!focusTaken) {
             </span><span style="color:#ff0000;"> performClick();</span><span style="color:#333333;">
       }
    }
    …
    break;</span></span>
可以看到,Click的觸發是在系統捕捉到ACTION_UP後發生並由performClick()執行的,performClick裏會調用先前註冊的監聽器的onClick()方法:

<span style="font-size:14px;">public boolean performClick() {
    …
    if (mOnClickListener != null) {
        playSoundEffect(SoundEffectConstants.CLICK);
        <span style="color:#3366ff;">mOnClickListener.onClick(this);</span>
        return true;
    }</span>
<span style="font-size:14px;">        return false;
}</span>

ongClick的觸發則是從ACTION_DOWN開始,由postCheckForLongClick()方法完成:

<span style="color:#333333;">private void postCheckForLongClick() {
     mHasPerformedLongPress = false;
     if (mPendingCheckForLongPress == null) {
         mPendingCheckForLongPress = new CheckForLongPress();
     }
     mPendingCheckForLongPress.rememberWindowAttachCount();
    </span><span style="color:#3366ff;"> postDelayed(mPendingCheckForLongPress, ViewConfiguration.getLongPressTimeout());</span><span style="color:#333333;">
}</span>

可以看到,在ACTION_DOWN事件被捕捉後,系統會開始觸發一個postDelayed操作,delay的時間在Eclair2.1上爲500ms500ms後會觸發CheckForLongPress線程的執行:

<span style="font-size:14px;"><span style="color:#333333;">class CheckForLongPress implements Runnable {
…
        public void run() {
            if (isPressed() && (mParent != null)
                    && mOriginalWindowAttachCount == mWindowAttachCount) {
                if (</span><span style="color:#3366ff;">performLongClick()</span><span style="color:#333333;">) {
                    mHasPerformedLongPress = true;
                }
            }
        }
…
}</span></span>
如果各種條件都滿足,那麼在CheckForLongPress中執行performLongClick(),在這個方法中將調用onLongClick()

<span style="color:#333333;">public boolean performLongClick() {
      …
      if (mOnLongClickListener != null) {
          </span><span style="color:#3366ff;">handled = mOnLongClickListener.onLongClick(View.this);</span><span style="color:#333333;">
      }
      …
}</span>


Button的onTouch,onClick,onLongClick事件發生先後順序和關聯:

注意: onTouch事件中:down事件返回值標記此次事件是否爲點擊事件,返回false說明是點擊事件,返回true不記爲點擊事件;up事件標記此次事件結束時間,也就是判斷是否爲長按。

一. onTouch返回false,執行順序

1.如果長按:down-->onLongClick-->up-->onClick

2.如果點擊:down-->up-->onClick

二. onTouch返回true,執行順序:down-->up,不會觸發onclick以及onLongClick

三. onTouch:down返回true,up返回false執行順序結果同二:down-->up,不會觸發onclick以及onLongClick
       機制分析:   onTouch事件中:down返回true,系統將不把本次事件記錄爲點擊事件,也就不會觸發onClick或者onLongClick事件了。因此儘管當up的時候返回false,系統也不會繼續觸發onClick事件了。

四.onTouch:down返回false,up返回true執行順序:

1.如果長按:down-->onLongClick-->up

2.如果點擊:down-->up------>(達到一定時間後自動觸發onLongClick)

      機制分析:  onTouch事件中:down返回false,說明此次事件爲點擊事件,而up返回了true,說明此次事件一直沒有結束,也就是一直長按下去了,達到長按臨界時間後,自然觸發長按事件,而onClick事件沒有觸發到


結論:1.ontouch的down事件返回true一定不會觸發onclick事件

2.ontouch的down事件返回false,up事件返回ture一定會觸發onLongClick事件,並且不會觸發onclick事件(因爲up返回true長按事件會一直自動執行下去)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章