view事件分發(fā)源代碼詳解

view事件分發(fā)

1,首先 viewgroup并沒有重寫onTouchEvent 方法,而viewgroup是view 的子類,所以view的onTouchEvent 方法也是veiwgroup的方法

2, view 沒有onInterceptTouchEvent,方法,因?yàn)樗恍枰獢r截事件,

首先看下 onDispatchTouchEvent方法源代碼

public boolean dispatchTouchEvent(MotionEvent event) {

//記錄最后的處理結(jié)果

boolean result = false;

//這是一個(gè)驗(yàn)證事件完整性的一個(gè)類,一會(huì)會(huì)看到在本方法結(jié)束的地方也有這個(gè)類出現(xiàn)

//防止event事件在分發(fā)過程中不一致,這個(gè)類還有記錄的功能

?if (mInputEventConsistencyVerifier != null) {

?mInputEventConsistencyVerifier.onTouchEvent(event, 0);

?}

//活動(dòng)事件種類

final int actionMasked = event.getActionMasked();

//如果是down 就停止

if (actionMasked == MotionEvent.ACTION_DOWN) {

// Defensive cleanup for new gesture

stopNestedScroll(); //停止view中嵌套的滑動(dòng)

}

//view 為 enable,并且事件可以被scroll bar 處理掉時(shí),返回true

//表示事件被滑動(dòng)所消耗掉了

if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {

result = true;

}

//這個(gè) li中保存了各種我們?yōu)関iew設(shè)置的listener

ListenerInfo li = mListenerInfo;

//先調(diào)用OnTouchListener的 onTouch ,返回true表示事件被消耗了

if (li != null && li.mOnTouchListener != null

&& (mViewFlags & ENABLED_MASK) == ENABLED

&& li.mOnTouchListener.onTouch(this, event)) {

result = true;

}

//看到這里就知道,如果 onTouchListener的onTouch返回true,消耗掉了事件,就不會(huì)在回調(diào)

//onTouchEvent了

if (!result && onTouchEvent(event)) {

result = true;

}

//表示事件沒被處理,和之前的事件校驗(yàn)器相對應(yīng)

if (!result && mInputEventConsistencyVerifier != null) {

mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);

}

//如果抬起事件和取消事件,及down事件卻沒有消耗掉, 同樣都要取消掉滑動(dòng)

if (actionMasked == MotionEvent.ACTION_UP ||

actionMasked == MotionEvent.ACTION_CANCEL ||

(actionMasked == MotionEvent.ACTION_DOWN && !result)) {

stopNestedScroll();

}

//分發(fā)結(jié)束

return result;

}

接下來看 ontouchEvent()

這里有幾種狀態(tài) : click press longclick longpass

click 和 press 由up down 組成

longpass 由 up down 組成,但是兩個(gè)事件之間有延時(shí),一定不能有move

longclick 由 up down move 組成, move可有可無

public boolean onTouchEvent(MotionEvent event) {

//獲取event的坐標(biāo),事件類型,及view的狀態(tài)標(biāo)志 mViewFlags,它通過位運(yùn)算存儲(chǔ)不同的狀態(tài)

final float x = event.getX();

final float y = event.getY();

final int viewFlags = mViewFlags;

final int action = event.getAction();

//view處于disable狀態(tài),能接受到事件,但是沒有任何處理...

if ((viewFlags & ENABLED_MASK) == DISABLED) {

if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {

setPressed(false); //傳入false 表示還原之前 pass 狀態(tài)

}

// 一個(gè) view 是 disable 且 clickable 仍然會(huì)消耗事件,只是沒有任何響應(yīng)

return (((viewFlags & CLICKABLE) == CLICKABLE

|| (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)

|| (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE);

}

if (mTouchDelegate != null) {

//代理來理事件,會(huì)把事件交給調(diào)用代理的view

//代理使view可以處理的事件的接觸面積變大.但其實(shí)還是調(diào)用view自己的實(shí)際處理方法

if (mTouchDelegate.onTouchEvent(event)) {

return true;

}

}

//判斷是否可點(diǎn),是否可長按,上下文是否可點(diǎn) 任意為真就可以消耗事件,否則表示不消耗事件

if (((viewFlags & CLICKABLE) == CLICKABLE ||

(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||

(viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {

switch (action) {

case MotionEvent.ACTION_DOWN: //這里調(diào)換了源代碼的順序

mHasPerformedLongPress = false; //是否執(zhí)行長按事件

//看是否view是butten類似的控件,能否消耗掉點(diǎn)擊事件-不太明白

if (performButtonActionOnTouchDown(event)) {

break;

}

//判斷是否在滾動(dòng)容器中

boolean isInScrollingContainer = isInScrollingContainer();

if (isInScrollingContainer) {

// //mPrivateFlags 設(shè)置為 PFLAG_PREPRESSED(pass的前狀態(tài),后邊會(huì)用到)

mPrivateFlags |= PFLAG_PREPRESSED;

if (mPendingCheckForTap == null) {

//異步執(zhí)行pass狀態(tài),及延時(shí)設(shè)置longClick狀態(tài)

//longclick狀態(tài)有他自己的延時(shí)時(shí)長,

mPendingCheckForTap = new CheckForTap();

}

mPendingCheckForTap.x = event.getX();

mPendingCheckForTap.y = event.getY();

//延時(shí)設(shè)置pass及l(fā)ongclick狀態(tài).

postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());

} else { 不在滑動(dòng)中,直接設(shè)置press 及l(fā)ongclick狀態(tài)

// Not inside a scrolling container, so show the feedback right away

//不在滑動(dòng)中,立刻設(shè)置為press狀態(tài),同時(shí)設(shè)置為longclick狀態(tài)

setPressed(true, x, y);

//檢查執(zhí)行長按,longclick有他自己的延時(shí)時(shí)間

checkForLongClick(0, x, y);

}

break;

case MotionEvent.ACTION_CANCEL://重置所有狀態(tài)

setPressed(false); //還原之前的press狀態(tài)

removeTapCallback();//還原 輕按狀態(tài)

removeLongPressCallback();//還原longclick狀態(tài)

mInContextButtonPress = false;

mHasPerformedLongPress = false;

mIgnoreNextUpEvent = false;

break;

case MotionEvent.ACTION_MOVE:

//提醒子view(如果有)觸摸點(diǎn)坐標(biāo)變換了

drawableHotspotChanged(x, y);

//移動(dòng)到了按鈕外邊

if (!pointInView(x, y, mTouchSlop)) {

// 移除tap回調(diào)

removeTapCallback();

//如果view為press狀態(tài)

if ((mPrivateFlags & PFLAG_PRESSED) != 0) {

//還原 longclick和 press 狀態(tài)

removeLongPressCallback();

setPressed(false);

}

}

case MotionEvent.ACTION_UP:

//是否為 prepress 狀態(tài)

boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;

if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {

//press狀態(tài)或者 prePass 狀態(tài)

boolean focusTaken = false;

// view 獲取焦點(diǎn)

if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {

focusTaken = requestFocus(); //重新獲取焦點(diǎn)

}

//之前為prepress 在up時(shí)就變更為press

if (prepressed) {

setPressed(true, x, y);

}

//移除longPass 狀態(tài)

if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {

removeLongPressCallback();

if (!focusTaken) { //沒有獲取焦點(diǎn) 有可能表示view 不接受輸入

//異步發(fā)送一個(gè)點(diǎn)擊事件,調(diào)用 clicklistener 的 onclick 方法

if (mPerformClick == null) {

mPerformClick = new PerformClick();

}

//

if (!post(mPerformClick)) {

//異步發(fā)送失敗,則手動(dòng)發(fā)送點(diǎn)擊事件

performClick(); //調(diào)用click 方法

}

}

}

//一個(gè)異步還原press的 runnable類

if (mUnsetPressedState == null) {

mUnsetPressedState = new UnsetPressedState();

}

//異步還原pass 狀態(tài),如果失敗就手動(dòng)調(diào)用

if (prepressed) {

postDelayed(mUnsetPressedState,

ViewConfiguration.getPressedStateDuration());

} else if (!post(mUnsetPressedState)) {

// If the post failed, unpress right now

mUnsetPressedState.run();

}

removeTapCallback(); //移除tap狀態(tài)

mIgnoreNextUpEvent = false;

break;

}

return true;

}

return false;

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容