在Android中,onClick、onLongClick的觸發是和ACTION_DOWN及ACTION_UP相關的,在時序上,如果我們在一個View中同時覆寫了onClick、onLongClick及onTouchEvent的話,onTouchEvent是最先捕捉到ACTION_DOWN和ACTION_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上爲500ms,500ms後會觸發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長按事件會一直自動執行下去)