尊重原创: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有关的方法

@Overridepublic 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

@Overridepublic 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 startedmLastMotionX = 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 + ")\nmIsBeingDragged:" + 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 eventfinal 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 componentmLastMotionX += 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 behaviorfinal 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 menusetCurrentItem(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滑动了)


更多相关文章

  1. Android(Java):Android 事件分发机制
  2. android 回车键事件编程
  3. Android 事件分发机制源码
  4. android 回车键事件
  5. Android事件分发机制详解:史上最全面、最易懂
  6. 【Android 1.6】View和ViewGroup的touch事件分析和总结
  7. Android的Activity屏幕切换动画||GestureDetector、OnGestureLis

随机推荐

  1. 周杰伦新歌《说好不哭》深夜上线挤崩QQ音
  2. 承认吧,程序员就是比你有钱,又比你会过日子
  3. Java程序员必备基础:Object的十二个知识点
  4. Steam将上架KFC恋爱模拟器,你要和肯德基老
  5. 聊聊如何从程序员晋升为管理者(我的肺腑之
  6. 「什么值得买」网站挂了,疑程序员删库跑路
  7. MySQL也要删“blacklist”,万万没想到技术
  8. JAVA程序一次句柄泄露问题分析
  9. 微信转账后被拉黑该如何追回?官方这些隐藏
  10. 一大波开发者福利!谷歌宣布在中国正式推出