1.setOnTouchListener true 在OnTouchListener 的onTouch 处截断,不往下走,onTouchEvent 设置不起作用 a.onTouchEvent false E/MyButton: dispatchTouchEvent ACTION_DOWN E/TAG: onTouch execute, action 0 E/MyButton: dispatchTouchEvent ACTION_UP E/TAG: onTouch execute, action 1 b.onTouchEvent true E/MyButton: dispatchTouchEvent ACTION_DOWN E/TAG: onTouch execute, action 0 E/MyButton: dispatchTouchEvent ACTION_UP E/TAG: onTouch execute, action 1 1.setOnTouchListener false a.onTouchEvent false 走完第一次onTouchEvent,不在监听 dispatchTouchEvent ACTION_UP E/MyButton: dispatchTouchEvent ACTION_DOWN E/TAG: onTouch execute, action 0 E/MyButton: onTouchEvent ACTION_DOWN b.onTouchEvent true E/MyButton: dispatchTouchEvent ACTION_DOWN E/TAG: onTouch execute, action 0 E/MyButton: onTouchEvent ACTION_DOWN E/MyButton: dispatchTouchEvent ACTION_UP E/TAG: onTouch execute, action 1 E/MyButton: onTouchEvent ACTION_UP c.onTouchEvent super.onTouchEvent(event) E/MyButton: dispatchTouchEvent ACTION_DOWN E/TAG: onTouch execute, action 0 E/MyButton: onTouchEvent ACTION_DOWN E/MyButton: dispatchTouchEvent ACTION_UP E/TAG: onTouch execute, action 1 E/MyButton: onTouchEvent ACTION_UP E/TAG: onClick execute */
View
1. dispatchTouchEvent
流程:1.mOnTouchListener.onTouch(this, event) 2. onTouchEvent(event)方法 3.onClick()
/** * 1.mOnTouchListener 不为空 2.ENABLED可点击, 2.onTouch(this, event)设置ture,对此事件处理(拦截) 那么事件将不会继续往下分发 */ if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { return true; } /** * 1. 如果mOnTouchListener不为空, 事件先在mOnTouchListener 的onTouch(this, event)处理了一遍 * 2. 事件交由view的onTouchEvent方法处理,如果true, 那么事件将不会继续往下分发 */ if (onTouchEvent(event)) { return true; }
2. onTouchEvent(event)
3. public boolean onTouchEvent(MotionEvent event) { final int viewFlags = mViewFlags; if ((viewFlags & ENABLED_MASK) == DISABLED) { if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { setPressed(false); } // A disabled view that is clickable still consumes the touch // events, it just doesn't respond to them. /** * 1. 可点击,但是DISABLED, * 2.仍然消费touch事件,只是不作出回应。 */ return (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)); } if (mTouchDelegate != null) { if (mTouchDelegate.onTouchEvent(event)) { return true; } } if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) { switch (event.getAction()) { case MotionEvent.ACTION_UP: /** * 1.mPrivateFlags 包含PFLAG_PREPRESSED,或者包含PFLAG_PRESSED 则进入 * 115ms内或者之后抬起都会进入执行体。 * */ 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); } /** * 1. 没有执行长按, * 或者没有监听, * 或者 mOnLongClickListener.onLongClick(View.this)返回false * 则移除 延时长按任务 * 2. 如果没有将点击任务加到队列中,则直接调用点击事件onClick */ if (!mHasPerformedLongPress) { // This is a tap, so remove the longpress check removeLongPressCallback(); // Only perform take click actions if we were in the pressed state if (!focusTaken) { // Use a Runnable and post this rather than calling // performClick directly. This lets other visual state // of the view update before click actions start. if (mPerformClick == null) { mPerformClick = new PerformClick(); } if (!post(mPerformClick)) { performClick(); } } } // 建立任务 //从 mPrivateFlags标签中 移除PFLAG_PRESSED 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(); } break; case MotionEvent.ACTION_DOWN: mHasPerformedLongPress = false; 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) { mPrivateFlags |= PFLAG_PREPRESSED; if (mPendingCheckForTap == null) { mPendingCheckForTap = new CheckForTap(); } postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); } else { // Not inside a scrolling container, so show the feedback right away setPressed(true); checkForLongClick(0); } break; case MotionEvent.ACTION_CANCEL: setPressed(false); removeTapCallback(); removeLongPressCallback(); break; case MotionEvent.ACTION_MOVE: final int x = (int) event.getX(); final int y = (int) event.getY(); // Be lenient about moving outside of buttons /** * 1.如果点击点在 view 范围内,进入执行体 * 2.标签是否 包含PFLAG_PRESSED 有 表明设置过,并有延时长按任务 * 3.移除长按任务 * 4.移除PFLAG_PRESSED */ if (!pointInView(x, y, mTouchSlop)) { // Outside button removeTapCallback(); if ((mPrivateFlags & PFLAG_PRESSED) != 0) { // Remove any future long press/tap checks removeLongPressCallback(); setPressed(false); } } break; } return true; } return false; }