菜鸟进阶Android Touch事件传递(四)

尊重他人劳动成果,转载请说明出处:http://blog.csdn.net/bingospunky/article/details/44343477

在该系列文章第四篇。我准备介绍一下viewpager的touch事件处理。

假设想了解touch和click的那些事,请浏览touch事件传递系列的第一篇http://blog.csdn.net/bingospunky/article/details/43603397

假设想了解touch事件一步一步传递的路线,请浏览touch事件传递系列的第二篇http://blog.csdn.net/bingospunky/article/details/43735497

假设想从源代码角度什么理解viewgroup的dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent怎样实现。请浏览touch事件传递系列的第二篇http://blog.csdn.net/bingospunky/article/details/44156771

源代码

代码A:boolean android.support.v4.view.ViewPager.onInterceptTouchEvent(MotionEvent ev)

  1. public boolean onInterceptTouchEvent(MotionEvent ev) {
  2. /*
  3. * This method JUST determines whether we want to intercept the motion.
  4. * If we return true, onMotionEvent will be called and we do the actual
  5. * scrolling there.
  6. */
  7. final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
  8. // Always take care of the touch gesture being complete.
  9. if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
  10. // Release the drag.
  11. if (DEBUG) Log.v(TAG, "Intercept done!");
  12. mIsBeingDragged = false;
  13. mIsUnableToDrag = false;
  14. mActivePointerId = INVALID_POINTER;
  15. if (mVelocityTracker != null) {
  16. mVelocityTracker.recycle();
  17. mVelocityTracker = null;
  18. }
  19. return false;
  20. }
  21. // Nothing more to do here if we have decided whether or not we
  22. // are dragging.
  23. if (action != MotionEvent.ACTION_DOWN) {
  24. if (mIsBeingDragged) {
  25. if (DEBUG) Log.v(TAG, "Intercept returning true!");
  26. return true;
  27. }
  28. if (mIsUnableToDrag) {
  29. if (DEBUG) Log.v(TAG, "Intercept returning false!");
  30. return false;
  31. }
  32. }
  33. switch (action) {
  34. case MotionEvent.ACTION_MOVE: {
  35. /*
  36. * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
  37. * whether the user has moved far enough from his original down touch.
  38. */
  39. /*
  40. * Locally do absolute value. mLastMotionY is set to the y value
  41. * of the down event.
  42. */
  43. final int activePointerId = mActivePointerId;
  44. if (activePointerId == INVALID_POINTER) {
  45. // If we don't have a valid id, the touch down wasn't on content.
  46. break;
  47. }
  48. final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId);
  49. final float x = MotionEventCompat.getX(ev, pointerIndex);
  50. final float dx = x - mLastMotionX;
  51. final float xDiff = Math.abs(dx);
  52. final float y = MotionEventCompat.getY(ev, pointerIndex);
  53. final float yDiff = Math.abs(y - mInitialMotionY);
  54. if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
  55. if (dx != 0 && !isGutterDrag(mLastMotionX, dx) &&
  56. canScroll(this, false, (int) dx, (int) x, (int) y)) {
  57. // Nested view has scrollable area under this point. Let it be handled there.
  58. mLastMotionX = x;
  59. mLastMotionY = y;
  60. mIsUnableToDrag = true;
  61. return false;
  62. }
  63. if (xDiff > mTouchSlop && xDiff * 0.5f > yDiff) {
  64. if (DEBUG) Log.v(TAG, "Starting drag!");
  65. mIsBeingDragged = true;
  66. requestParentDisallowInterceptTouchEvent(true);
  67. setScrollState(SCROLL_STATE_DRAGGING);
  68. mLastMotionX = dx > 0 ? mInitialMotionX + mTouchSlop :
  69. mInitialMotionX - mTouchSlop;
  70. mLastMotionY = y;
  71. setScrollingCacheEnabled(true);
  72. } else if (yDiff > mTouchSlop) {
  73. // The finger has moved enough in the vertical
  74. // direction to be counted as a drag...  abort
  75. // any attempt to drag horizontally, to work correctly
  76. // with children that have scrolling containers.
  77. if (DEBUG) Log.v(TAG, "Starting unable to drag!");
  78. mIsUnableToDrag = true;
  79. }
  80. if (mIsBeingDragged) {
  81. // Scroll to follow the motion event
  82. if (performDrag(x)) {
  83. ViewCompat.postInvalidateOnAnimation(this);
  84. }
  85. }
  86. break;
  87. }
  88. case MotionEvent.ACTION_DOWN: {
  89. /*
  90. * Remember location of down touch.
  91. * ACTION_DOWN always refers to pointer index 0.
  92. */
  93. mLastMotionX = mInitialMotionX = ev.getX();
  94. mLastMotionY = mInitialMotionY = ev.getY();
  95. mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
  96. mIsUnableToDrag = false;
  97. mScroller.computeScrollOffset();
  98. if (mScrollState == SCROLL_STATE_SETTLING &&
  99. Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) {
  100. // Let the user 'catch' the pager as it animates.
  101. mScroller.abortAnimation();
  102. mPopulatePending = false;
  103. populate();
  104. mIsBeingDragged = true;
  105. requestParentDisallowInterceptTouchEvent(true);
  106. setScrollState(SCROLL_STATE_DRAGGING);
  107. } else {
  108. completeScroll(false);
  109. mIsBeingDragged = false;
  110. }
  111. if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY
  112. + " mIsBeingDragged=" + mIsBeingDragged
  113. + "mIsUnableToDrag=" + mIsUnableToDrag);
  114. break;
  115. }
  116. case MotionEventCompat.ACTION_POINTER_UP:
  117. onSecondaryPointerUp(ev);
  118. break;
  119. }
  120. if (mVelocityTracker == null) {
  121. mVelocityTracker = VelocityTracker.obtain();
  122. }
  123. mVelocityTracker.addMovement(ev);
  124. /*
  125. * The only time we want to intercept motion events is if we are in the
  126. * drag mode.
  127. */
  128. return mIsBeingDragged;
  129. }

代码B:boolean android.support.v4.view.ViewPager.onTouchEvent(MotionEvent ev)

  1. public boolean onTouchEvent(MotionEvent ev) {
  2. if (mFakeDragging) {
  3. // A fake drag is in progress already, ignore this real one
  4. // but still eat the touch events.
  5. // (It is likely that the user is multi-touching the screen.)
  6. return true;
  7. }
  8. if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
  9. // Don't handle edge touches immediately -- they may actually belong to one of our
  10. // descendants.
  11. return false;
  12. }
  13. if (mAdapter == null || mAdapter.getCount() == 0) {
  14. // Nothing to present or scroll; nothing to touch.
  15. return false;
  16. }
  17. if (mVelocityTracker == null) {
  18. mVelocityTracker = VelocityTracker.obtain();
  19. }
  20. mVelocityTracker.addMovement(ev);
  21. final int action = ev.getAction();
  22. boolean needsInvalidate = false;
  23. switch (action & MotionEventCompat.ACTION_MASK) {
  24. case MotionEvent.ACTION_DOWN: {
  25. mScroller.abortAnimation();
  26. mPopulatePending = false;
  27. populate();
  28. // Remember where the motion event started
  29. mLastMotionX = mInitialMotionX = ev.getX();
  30. mLastMotionY = mInitialMotionY = ev.getY();
  31. mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
  32. break;
  33. }
  34. case MotionEvent.ACTION_MOVE:
  35. if (!mIsBeingDragged) {
  36. final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
  37. final float x = MotionEventCompat.getX(ev, pointerIndex);
  38. final float xDiff = Math.abs(x - mLastMotionX);
  39. final float y = MotionEventCompat.getY(ev, pointerIndex);
  40. final float yDiff = Math.abs(y - mLastMotionY);
  41. if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
  42. if (xDiff > mTouchSlop && xDiff > yDiff) {
  43. if (DEBUG) Log.v(TAG, "Starting drag!");
  44. mIsBeingDragged = true;
  45. requestParentDisallowInterceptTouchEvent(true);
  46. mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop :
  47. mInitialMotionX - mTouchSlop;
  48. mLastMotionY = y;
  49. setScrollState(SCROLL_STATE_DRAGGING);
  50. setScrollingCacheEnabled(true);
  51. // Disallow Parent Intercept, just in case
  52. ViewParent parent = getParent();
  53. if (parent != null) {
  54. parent.requestDisallowInterceptTouchEvent(true);
  55. }
  56. }
  57. }
  58. // Not else! Note that mIsBeingDragged can be set above.
  59. if (mIsBeingDragged) {
  60. // Scroll to follow the motion event
  61. final int activePointerIndex = MotionEventCompat.findPointerIndex(
  62. ev, mActivePointerId);
  63. final float x = MotionEventCompat.getX(ev, activePointerIndex);
  64. needsInvalidate |= performDrag(x);
  65. }
  66. break;
  67. case MotionEvent.ACTION_UP:
  68. if (mIsBeingDragged) {
  69. final VelocityTracker velocityTracker = mVelocityTracker;
  70. velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
  71. int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(
  72. velocityTracker, mActivePointerId);
  73. mPopulatePending = true;
  74. final int width = getClientWidth();
  75. final int scrollX = getScrollX();
  76. final ItemInfo ii = infoForCurrentScrollPosition();
  77. final int currentPage = ii.position;
  78. final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;
  79. final int activePointerIndex =
  80. MotionEventCompat.findPointerIndex(ev, mActivePointerId);
  81. final float x = MotionEventCompat.getX(ev, activePointerIndex);
  82. final int totalDelta = (int) (x - mInitialMotionX);
  83. int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
  84. totalDelta);
  85. setCurrentItemInternal(nextPage, true, true, initialVelocity);
  86. mActivePointerId = INVALID_POINTER;
  87. endDrag();
  88. needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
  89. }
  90. break;
  91. case MotionEvent.ACTION_CANCEL:
  92. if (mIsBeingDragged) {
  93. scrollToItem(mCurItem, true, 0, false);
  94. mActivePointerId = INVALID_POINTER;
  95. endDrag();
  96. needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
  97. }
  98. break;
  99. case MotionEventCompat.ACTION_POINTER_DOWN: {
  100. final int index = MotionEventCompat.getActionIndex(ev);
  101. final float x = MotionEventCompat.getX(ev, index);
  102. mLastMotionX = x;
  103. mActivePointerId = MotionEventCompat.getPointerId(ev, index);
  104. break;
  105. }
  106. case MotionEventCompat.ACTION_POINTER_UP:
  107. onSecondaryPointerUp(ev);
  108. mLastMotionX = MotionEventCompat.getX(ev,
  109. MotionEventCompat.findPointerIndex(ev, mActivePointerId));
  110. break;
  111. }
  112. if (needsInvalidate) {
  113. ViewCompat.postInvalidateOnAnimation(this);
  114. }
  115. return true;
  116. }

代码C:void android.support.v4.view.ViewPager.onSecondaryPointerUp(MotionEvent ev)

  1. private void onSecondaryPointerUp(MotionEvent ev) {
  2. final int pointerIndex = MotionEventCompat.getActionIndex(ev);
  3. final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
  4. if (pointerId == mActivePointerId) {
  5. // This was our active pointer going up. Choose a new
  6. // active pointer and adjust accordingly.
  7. final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
  8. mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex);
  9. mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
  10. if (mVelocityTracker != null) {
  11. mVelocityTracker.clear();
  12. }
  13. }
  14. }

总结

在这里就不想上篇文章那样分各种情况去讨论了。那样有些无聊。这里就重要点的说明一下我的理解,最后附一个我写的demo供大家參考学习。

1、viewpager处理touch的思路:不截断touch。假设touch移动满足了一定的条件,再截断touch由该viewgroup处理。

2、我们能够看到onInterceptTouchEvent和onTouchEvent方法里的方法非常相似。对于一个touch事件。这两个方法基本不会被都运行。仅仅有非常少的情况下这两个方法都会被运行。

3、viewpager有趣的现象。操作:单点操作viewpager。使viewpager响应事件,再加一个点触碰viewpager。如此不断加点,能够看到viewpager响应后加上去点的事件,这是为什么呢?代码B第108--111行已经告诉我们了,不再解释。

4、viewpager有趣的现象。操作:对于前面不不断加上去的触点,假设如今一共同拥有4个触点。如今响应第4个触点的事件,假设第4个触点抬起,那么viewpager响应哪个触点的事件呢?答案是第一个。

规律是什么呢?抬起的触点不是当前响应的。那么没影响;假设是当前响应的:假设抬起的触点的pointerIndex不是0,那么由pointerIndex最小的触点来响应,所以由第一个来响应。代码C已经非常明显告诉我们了。

假设这里你看不懂,那么你要学习一下android是怎么处理多触点事件的就会明确了。

Demo

下载地址:http://download.csdn.net/detail/u011647962/8507523

版权声明:本文博主原创文章。转载请注明出处。

上一篇:无废话WCF入门教程二[WCF应用的通信过程]


下一篇:IntelliJ IDEA WEB项目的部署配置