android事件分發之view.onTouchEvent

這是android事件分法機制的最后一個重要的方法,一般自定義的視圖都要往這里開刀,開個玩笑;ontouchevent方法消費事件的場合,無論消費的對象是viewgroup還是view都要調用該方法;那么默認的,view類在這個方法里做了什么呢?我們都知道OnClickListener和OnLongClickListener這兩種事件監聽器吧,對,你猜的不錯,實現的機制就是在這個方法里面,讓我們來看看吧。

第一步:分析viewFlags屬性信息判斷是否是可點擊(clickable);第二步,如果當前的視圖設置enable為false,但是視圖是可點擊的(clickable),我們還是認為它消費了該事件,否則是不消費,無論是否消費,在enable是false的情況下,它是直接返回的,也就不會響應onClick事件之類的;第三步,如果該視圖將事件委托給了其他視圖進行處理,那么讓被委托的視圖進行處理,自己就不處理了;接下來進入主題了:

//如果此視圖是可點擊的或者他的提示框是顯示的,那么進入里面做進一步處理

if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {

? ? switch (action) {

? ? ? ? case MotionEvent.ACTION_UP:

? ? ? ? ? ? mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;

? ? ? ? ? //如果是提示框顯示,那么讓他處理按起事件

? ? ? ? ? ? if ((viewFlags & TOOLTIP) == TOOLTIP) {

? ? ? ? ? ? ? ? handleTooltipUp();

? ? ? ? ? ? }

? ? ? ? ? ? if (!clickable) {

? ? ? ? ? ? ? ? removeTapCallback();

? ? ? ? ? ? ? ? removeLongPressCallback();

? ? ? ? ? ? ? ? mInContextButtonPress = false;

? ? ? ? ? ? ? ? mHasPerformedLongPress = false;

? ? ? ? ? ? ? ? mIgnoreNextUpEvent = false;

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? }

? ? ? ? ? //記錄該視圖響應按下的事件

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

? ? ? ? ? //如果事件沒有超出邊框,并且響應了按下事件,那么響應點擊事件

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

? ? ? ? ? ? ? ? // take focus if we don't have it already and we should in

? ? ? ? ? ? ? ? // touch mode.

? ? ? ? ? ? ? ? boolean focusTaken = false;

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

? ? ? ? ? ? ? ? ? ? focusTaken = requestFocus();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? if (prepressed) {

? ? ? ? ? ? ? ? ? ? // The button is being released before we actually

? ? ? ? ? ? ? ? ? ? // showed it as pressed.? Make it show the pressed

? ? ? ? ? ? ? ? ? ? // state now (before scheduling the click) to ensure

? ? ? ? ? ? ? ? ? ? // the user sees it.

? ? ? ? ? ? ? ? ? ? setPressed(true, x, y);

? ? ? ? ? ? ? ? }

//如果已經響應了長點擊事件,那么就不響應點擊事件

? ? ? ? ? ? ? ? if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {

? ? ? ? ? ? ? ? ? ?// 移除長點擊回調

? ? ? ? ? ? ? ? ? ? removeLongPressCallback();

? ? ? ? ? ? ? ? ? ? // Only perform take click actions if we were in the pressed state

? ? ? ? ? ? ? ? ? ? if (!focusTaken) {

? ? ? ? ? ? ? ? ? ? //響應點擊事件

? ? ? ? ? ? ? ? ? ? ? ? if (mPerformClick == null) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? mPerformClick = new PerformClick();

? ? ? ? ? ? ? ? ? ? ? ? }

//執行點擊操作

? ? ? ? ? ? ? ? ? ? ? ? if (!post(mPerformClick)) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? performClick();

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? if (mUnsetPressedState == null) {

? ? ? ? ? ? ? ? ? ? mUnsetPressedState = new UnsetPressedState();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? if (prepressed) {

? ? ? ? ? ? ? ? ? ? postDelayed(mUnsetPressedState,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ViewConfiguration.getPressedStateDuration());

? ? ? ? ? ? ? ? } else if (!post(mUnsetPressedState)) {

? ? ? ? ? ? ? ? ? ? // If the post failed, unpress right now

? ? ? ? ? ? ? ? ? ? mUnsetPressedState.run();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? removeTapCallback();

? ? ? ? ? ? }

? ? ? ? ? ? mIgnoreNextUpEvent = false;

? ? ? ? ? ? break;

? ? ? ? case MotionEvent.ACTION_DOWN:

//如果是事件來源是觸屏產生的,那么mPrivateFlags3標記為PFLAG3_FINGER_DOWN

? ? ? ? ? ? if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) {

? ? ? ? ? ? ? ? mPrivateFlags3 |= PFLAG3_FINGER_DOWN;

? ? ? ? ? ? }

//重置為false

? ? ? ? ? ? mHasPerformedLongPress = false;

? ? ? ? ? ? if (!clickable) {

? ? ? ? ? ? ? ? checkForLongClick(0, x, y);

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? }

? ? ? ? ? ? if (performButtonActionOnTouchDown(event)) {

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? }

? ? ? ? ? ? // Walk up the hierarchy to determine if we're inside a scrolling container.

? ? ? ? ? ? boolean isInScrollingContainer = isInScrollingContainer();

? ? ? ? ? ? // For views inside a scrolling container, delay the pressed feedback for

? ? ? ? ? ? // a short period in case this is a scroll.

? ? ? ? ? ? if (isInScrollingContainer) {

//按下時間大于taptimeout,那么進入長點擊響應事件

? ? ? ? ? ? ? ? mPrivateFlags |= PFLAG_PREPRESSED;

? ? ? ? ? ? ? ? if (mPendingCheckForTap == null) {

? ? ? ? ? ? ? ? ? ? mPendingCheckForTap = new CheckForTap();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? mPendingCheckForTap.x = event.getX();

? ? ? ? ? ? ? ? mPendingCheckForTap.y = event.getY();

? ? ? ? ? ? ? ? postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());

? ? ? ? ? ? } else {

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

? ? ? ? ? ? ? ? setPressed(true, x, y);

? ? ? ? ? ? ? ? checkForLongClick(0, x, y);

? ? ? ? ? ? }

? ? ? ? ? ? break;

? ? ? ? case MotionEvent.ACTION_CANCEL:

? ? ? ? ? ? if (clickable) {

? ? ? ? ? ? ? ? setPressed(false);

? ? ? ? ? ? }

? ? ? ? ? ? removeTapCallback();

? ? ? ? ? ? removeLongPressCallback();

? ? ? ? ? ? mInContextButtonPress = false;

? ? ? ? ? ? mHasPerformedLongPress = false;

? ? ? ? ? ? mIgnoreNextUpEvent = false;

? ? ? ? ? ? mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;

? ? ? ? ? ? break;

? ? ? ? case MotionEvent.ACTION_MOVE:

? ? ? ? ? ? if (clickable) {

? ? ? ? ? ? ? ? drawableHotspotChanged(x, y);

? ? ? ? ? ? }

? ? ? ? ? ? //超出視圖大小范圍,那么不會響應點擊或長點擊事件

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

? ? ? ? ? ? ? ? // Outside button

? ? ? ? ? ? ? ? // Remove any future long press/tap checks

? ? ? ? ? ? ? ? removeTapCallback();

? ? ? ? ? ? ? ? removeLongPressCallback();

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

? ? ? ? ? ? ? ? ? ? setPressed(false);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;

? ? ? ? ? ? }

? ? ? ? ? ? break;

? ? }

? ? return true;

}

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

推薦閱讀更多精彩內容