這是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;
}