多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > 互聯網 > Android Touch事件傳遞機制引發的血案

Android Touch事件傳遞機制引發的血案

來源:程序員人生   發布時間:2014-10-11 08:00:00 閱讀次數:3125次

尊重原創:http://blog.csdn.net/yuanzeyao/article/details/38942135


關于Android Touch事件傳遞機制我之前也寫過兩篇文章,自認為對Touche事件還是理解得比較清楚的,但是最近遇到的一個問題,讓我再次對Android Touche事件進行一次學習。

我的關于Android Touche事件傳遞機制的文章如下:

http://blog.csdn.net/yuanzeyao/article/details/37961997

http://blog.csdn.net/yuanzeyao/article/details/38025165


我在這兩篇文章中得出過以下結論:

1、如果一個view是clickable的,那么這個View的onTouchEvent是一定會返回true的,也就是說任何觸摸事件都會被消費掉

2、如果一個View對于ACTION_DOWN事件沒有消費掉(onTouchEvent 返回false),那么后續的ACTION_MOVE,ACTION_UP是都不會接受到的,也就是沒有機會處理這些事件,這些事件都是在父View里面給處理了

3、如果一個ViewGroup想要攔截事件(不讓事件傳遞到子View),那么它只需要改寫ViewGroup的onInterceptTouchEvent(MotionEvent ev) 方法,讓他返回true,或者調用requestDisallowInterceptTouchEvent(true);

4、Android中的Touche事件是從底層向上層傳遞的 Activity->DecorView->ViewGroup->View


理解了上面的問題,我們就開始看看我所遇到的問題吧,

在使用SlideMenu的時候,在中的Activity中僅僅放置一個TextView,你會發現SlideMenu無法滑動,當時通過頂部的Title可以滑動,由于對SlideMenu用的不是很熟,當時以為是SlideMenu的哪個屬性用錯了,后來一直沒有解決問題,直到一位網友說設置TextView的clickable為true就可以解決問題,我嘗試了一下,還真行!哈哈。。。,這個里面的原因你理解了嗎?如果沒有理解,請繼續往下看


按照我之前對Touche事件的理解,如果設置clickable,那么Touche事件肯定就被TextView給消費掉了,如果被TextView消費掉了,那么SlideMenu如何實現滑動?要解開這個問題答案,還是看看SlideMenu的源碼嗎


我們首先看看SlideMenu中CustomViewAbove和Touche有關的方法

@Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (!mEnabled) return false; final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; if (action == MotionEvent.ACTION_DOWN && DEBUG) Log.v(TAG, "Received ACTION_DOWN"); if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP || (action != MotionEvent.ACTION_DOWN && mIsUnableToDrag)) { endDrag(); return false; } switch (action) { case MotionEvent.ACTION_MOVE: try{ final int activePointerId = mActivePointerId; if (activePointerId == INVALID_POINTER) break; final int pointerIndex = this.getPointerIndex(ev, activePointerId); final float x = MotionEventCompat.getX(ev, pointerIndex); final float dx = x - mLastMotionX; final float xDiff = Math.abs(dx); final float y = MotionEventCompat.getY(ev, pointerIndex); final float yDiff = Math.abs(y - mLastMotionY); if (DEBUG) Log.v(TAG, "onInterceptTouch moved to:(" + x + ", " + y + "), diff:(" + xDiff + ", " + yDiff + "), mLastMotionX:" + mLastMotionX); if (xDiff > mTouchSlop && xDiff > yDiff && thisSlideAllowed(dx)) { if (DEBUG) Log.v(TAG, "Starting drag! from onInterceptTouch"); startDrag(); mLastMotionX = x; setScrollingCacheEnabled(true); } else if (yDiff > mTouchSlop) { mIsUnableToDrag = true; } } catch(IllegalArgumentException e) { e.printStackTrace(); } break; case MotionEvent.ACTION_DOWN: mActivePointerId = ev.getAction() & ((Build.VERSION.SDK_INT >= 8) ? MotionEvent.ACTION_POINTER_INDEX_MASK : MotionEvent.ACTION_POINTER_INDEX_MASK); mLastMotionX = mInitialMotionX = MotionEventCompat.getX(ev, mActivePointerId); mLastMotionY = MotionEventCompat.getY(ev, mActivePointerId); if (thisTouchAllowed(ev)) { mIsBeingDragged = false; mIsUnableToDrag = false; if (isMenuOpen() && mViewBehind.menuTouchInQuickReturn(mContent, mCurItem, ev.getX() + mScrollX)) { mQuickReturn = true; } } else { mIsUnableToDrag = true; } break; case MotionEventCompat.ACTION_POINTER_UP: onSecondaryPointerUp(ev); break; } if (!mIsBeingDragged) { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(ev); } return mIsBeingDragged || mQuickReturn; }

看看這個方法,這個方法里面有個邏輯就是當滑動到一定距離,就會返回true,也就是說會攔截滑動事件,第一個ACTION_DOWN肯定不會攔截。

再看看onToucheEvent.java

@Override public boolean onTouchEvent(MotionEvent ev) { if (!mEnabled) return false; // if (!mIsBeingDragged && !thisTouchAllowed(ev)) // return false; if (!mIsBeingDragged && !mQuickReturn) return false; final int action = ev.getAction(); if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(ev); switch (action & MotionEventCompat.ACTION_MASK) { case MotionEvent.ACTION_DOWN: /* * If being flinged and user touches, stop the fling. isFinished * will be false if being flinged. */ completeScroll(); // Remember where the motion event started mLastMotionX = mInitialMotionX = ev.getX(); mActivePointerId = MotionEventCompat.getPointerId(ev, 0); break; case MotionEvent.ACTION_MOVE: if (!mIsBeingDragged) { if (mActivePointerId == INVALID_POINTER) break; final int pointerIndex = getPointerIndex(ev, mActivePointerId); final float x = MotionEventCompat.getX(ev, pointerIndex); final float dx = x - mLastMotionX; final float xDiff = Math.abs(dx); final float y = MotionEventCompat.getY(ev, pointerIndex); final float yDiff = Math.abs(y - mLastMotionY); if (DEBUG) Log.v(TAG, "onTouch moved to:(" + x + ", " + y + "), diff:(" + xDiff + ", " + yDiff + ") mIsBeingDragged:" + mIsBeingDragged + ", mLastMotionX:" + mLastMotionX); if ((xDiff > mTouchSlop || (mQuickReturn && xDiff > mTouchSlop / 4)) && xDiff > yDiff && thisSlideAllowed(dx)) { if (DEBUG) Log.v(TAG, "Starting drag! from onTouch"); startDrag(); mLastMotionX = x; setScrollingCacheEnabled(true); } else { if (DEBUG) Log.v(TAG, "onTouch returning false"); return false; } } if (mIsBeingDragged) { // Scroll to follow the motion event final int activePointerIndex = getPointerIndex(ev, mActivePointerId); if (mActivePointerId == INVALID_POINTER) { break; } final float x = MotionEventCompat.getX(ev, activePointerIndex); final float deltaX = mLastMotionX - x; mLastMotionX = x; float oldScrollX = getScrollX(); float scrollX = oldScrollX + deltaX; final float leftBound = getLeftBound(); final float rightBound = getRightBound(); if (scrollX < leftBound) { scrollX = leftBound; } else if (scrollX > rightBound) { scrollX = rightBound; } // Don't lose the rounded component mLastMotionX += scrollX - (int) scrollX; scrollTo((int) scrollX, getScrollY()); pageScrolled((int) scrollX); } break; case MotionEvent.ACTION_UP: if (mIsBeingDragged) { final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); int initialVelocity = (int) VelocityTrackerCompat.getXVelocity( velocityTracker, mActivePointerId); final int scrollX = getScrollX(); // final int widthWithMargin = getWidth(); // final float pageOffset = (float) (scrollX % widthWithMargin) / widthWithMargin; // TODO test this. should get better flinging behavior final float pageOffset = (float) (scrollX - getDestScrollX(mCurItem)) / getBehindWidth(); final int activePointerIndex = getPointerIndex(ev, mActivePointerId); if (mActivePointerId != INVALID_POINTER) { final float x = MotionEventCompat.getX(ev, activePointerIndex); final int totalDelta = (int) (x - mInitialMotionX); int nextPage = determineTargetPage(pageOffset, initialVelocity, totalDelta); setCurrentItemInternal(nextPage, true, true, initialVelocity); } else { setCurrentItemInternal(mCurItem, true, true, initialVelocity); } mActivePointerId = INVALID_POINTER; endDrag(); } else if (mQuickReturn && mViewBehind.menuTouchInQuickReturn(mContent, mCurItem, ev.getX() + mScrollX)) { // close the menu setCurrentItem(1); endDrag(); } break; case MotionEvent.ACTION_CANCEL: if (mIsBeingDragged) { setCurrentItemInternal(mCurItem, true, true); mActivePointerId = INVALID_POINTER; endDrag(); } break; case MotionEventCompat.ACTION_POINTER_DOWN: { final int index = MotionEventCompat.getActionIndex(ev); final float x = MotionEventCompat.getX(ev, index); mLastMotionX = x; mActivePointerId = MotionEventCompat.getPointerId(ev, index); break; } case MotionEventCompat.ACTION_POINTER_UP: onSecondaryPointerUp(ev); int pointerIndex = this.getPointerIndex(ev, mActivePointerId); if (mActivePointerId == INVALID_POINTER) break; mLastMotionX = MotionEventCompat.getX(ev, pointerIndex); break; } return true; }

我們重點觀察ACTION_DWON事件,對于ACTION_DWON事件,SlideMenu是沒有攔截的,所以傳遞到了TextView,由于默認TextView是沒有clickable的,所以是不會消費這個事件,如果TextView不消費,那么事件就傳遞到了SlideMenu,但是我們發現在SlideMenu中也沒有消費這個事件,還記得我們上面的結論2嗎,根據結論2,我們知道后面的事件是傳遞不過來的,所以導致了SlideMenu無法滑動。


如果我們設置了clickable,那么第一個ACTION_DOWN就被TextView處理了,所以后面每個事件都會傳遞到TextView(前提是不被攔截,實際結果是被攔截,并被SlideMenu處理,所以SlideMenu滑動了)


生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 最近中文字幕2019高清免费 | 国产亚洲精品线观看77 | 一本大道道香蕉免费 | free性欧美tube视频 | 国产精彩视频 | 欧美日韩一区二区亚洲 | 亚洲欧美综合乱码精品成人网 | 国产一区欧美 | 日韩影院在线观看 | 在线欧美一级毛片免费观看 | 天堂色在线 | 亚洲无吗在线视频 | 国产h视频在线 | 欧美一区二区三区网站 | japanhdⅹxxxhd日本 | 日韩一区二区三区视频 | 国产欧美日韩在线观看一区二区三区 | 国产精品一区二区免费 | 亚洲人成在线影院 | 在线亚洲小视频 | 久久伊 | 欧美在线aa | 国产三级精品在线观看 | 精品福利一区二区三区免费视频 | 激情 黄 +色+成+人 | 五月天在线观看免费视频播放 | 尤物国产视频 | 欧美日韩永久久一区二区三区 | 91手机看片国产福利精品 | 伊人久久成人 | www.在线观看.com| 精品久久久久久无码中文字幕 | 亚色污| 亚洲欧美日韩在线 | 亚洲经典自拍 | 国产在线观看精品一区二区三区91 | 欧美日韩a级a | 久久91亚洲精品久久91综合 | 午夜一区二区三区 | 亚在线 | 高清欧美一区二区免费影视 |