尊重他人劳动成果,转载请说明出处: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)
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- /*
- * This method JUST determines whether we want to intercept the motion.
- * If we return true, onMotionEvent will be called and we do the actual
- * scrolling there.
- */
- final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
- // Always take care of the touch gesture being complete.
- if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
- // Release the drag.
- if (DEBUG) Log.v(TAG, "Intercept done!");
- mIsBeingDragged = false;
- mIsUnableToDrag = false;
- mActivePointerId = INVALID_POINTER;
- if (mVelocityTracker != null) {
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
- return false;
- }
- // Nothing more to do here if we have decided whether or not we
- // are dragging.
- if (action != MotionEvent.ACTION_DOWN) {
- if (mIsBeingDragged) {
- if (DEBUG) Log.v(TAG, "Intercept returning true!");
- return true;
- }
- if (mIsUnableToDrag) {
- if (DEBUG) Log.v(TAG, "Intercept returning false!");
- return false;
- }
- }
- switch (action) {
- case MotionEvent.ACTION_MOVE: {
- /*
- * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
- * whether the user has moved far enough from his original down touch.
- */
- /*
- * Locally do absolute value. mLastMotionY is set to the y value
- * of the down event.
- */
- final int activePointerId = mActivePointerId;
- if (activePointerId == INVALID_POINTER) {
- // If we don't have a valid id, the touch down wasn't on content.
- break;
- }
- final int pointerIndex = MotionEventCompat.findPointerIndex(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 - mInitialMotionY);
- if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
- if (dx != 0 && !isGutterDrag(mLastMotionX, dx) &&
- canScroll(this, false, (int) dx, (int) x, (int) y)) {
- // Nested view has scrollable area under this point. Let it be handled there.
- mLastMotionX = x;
- mLastMotionY = y;
- mIsUnableToDrag = true;
- return false;
- }
- if (xDiff > mTouchSlop && xDiff * 0.5f > yDiff) {
- if (DEBUG) Log.v(TAG, "Starting drag!");
- mIsBeingDragged = true;
- requestParentDisallowInterceptTouchEvent(true);
- setScrollState(SCROLL_STATE_DRAGGING);
- mLastMotionX = dx > 0 ? mInitialMotionX + mTouchSlop :
- mInitialMotionX - mTouchSlop;
- mLastMotionY = y;
- setScrollingCacheEnabled(true);
- } else if (yDiff > mTouchSlop) {
- // The finger has moved enough in the vertical
- // direction to be counted as a drag... abort
- // any attempt to drag horizontally, to work correctly
- // with children that have scrolling containers.
- if (DEBUG) Log.v(TAG, "Starting unable to drag!");
- mIsUnableToDrag = true;
- }
- if (mIsBeingDragged) {
- // Scroll to follow the motion event
- if (performDrag(x)) {
- ViewCompat.postInvalidateOnAnimation(this);
- }
- }
- break;
- }
- case MotionEvent.ACTION_DOWN: {
- /*
- * Remember location of down touch.
- * ACTION_DOWN always refers to pointer index 0.
- */
- mLastMotionX = mInitialMotionX = ev.getX();
- mLastMotionY = mInitialMotionY = ev.getY();
- mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
- mIsUnableToDrag = false;
- mScroller.computeScrollOffset();
- if (mScrollState == SCROLL_STATE_SETTLING &&
- Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) {
- // Let the user 'catch' the pager as it animates.
- mScroller.abortAnimation();
- mPopulatePending = false;
- populate();
- mIsBeingDragged = true;
- requestParentDisallowInterceptTouchEvent(true);
- setScrollState(SCROLL_STATE_DRAGGING);
- } else {
- completeScroll(false);
- mIsBeingDragged = false;
- }
- if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY
- + " mIsBeingDragged=" + mIsBeingDragged
- + "mIsUnableToDrag=" + mIsUnableToDrag);
- break;
- }
- case MotionEventCompat.ACTION_POINTER_UP:
- onSecondaryPointerUp(ev);
- break;
- }
- if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
- }
- mVelocityTracker.addMovement(ev);
- /*
- * The only time we want to intercept motion events is if we are in the
- * drag mode.
- */
- return mIsBeingDragged;
- }
代码B:boolean android.support.v4.view.ViewPager.onTouchEvent(MotionEvent ev)
- public boolean onTouchEvent(MotionEvent ev) {
- if (mFakeDragging) {
- // A fake drag is in progress already, ignore this real one
- // but still eat the touch events.
- // (It is likely that the user is multi-touching the screen.)
- return true;
- }
- if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
- // Don't handle edge touches immediately -- they may actually belong to one of our
- // descendants.
- return false;
- }
- if (mAdapter == null || mAdapter.getCount() == 0) {
- // Nothing to present or scroll; nothing to touch.
- return false;
- }
- if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
- }
- mVelocityTracker.addMovement(ev);
- final int action = ev.getAction();
- boolean needsInvalidate = false;
- switch (action & MotionEventCompat.ACTION_MASK) {
- case MotionEvent.ACTION_DOWN: {
- mScroller.abortAnimation();
- mPopulatePending = false;
- populate();
- // Remember where the motion event started
- mLastMotionX = mInitialMotionX = ev.getX();
- mLastMotionY = mInitialMotionY = ev.getY();
- mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
- break;
- }
- case MotionEvent.ACTION_MOVE:
- if (!mIsBeingDragged) {
- final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
- final float x = MotionEventCompat.getX(ev, pointerIndex);
- final float xDiff = Math.abs(x - mLastMotionX);
- final float y = MotionEventCompat.getY(ev, pointerIndex);
- final float yDiff = Math.abs(y - mLastMotionY);
- if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
- if (xDiff > mTouchSlop && xDiff > yDiff) {
- if (DEBUG) Log.v(TAG, "Starting drag!");
- mIsBeingDragged = true;
- requestParentDisallowInterceptTouchEvent(true);
- mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop :
- mInitialMotionX - mTouchSlop;
- mLastMotionY = y;
- setScrollState(SCROLL_STATE_DRAGGING);
- setScrollingCacheEnabled(true);
- // Disallow Parent Intercept, just in case
- ViewParent parent = getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
- }
- }
- // Not else! Note that mIsBeingDragged can be set above.
- if (mIsBeingDragged) {
- // Scroll to follow the motion event
- final int activePointerIndex = MotionEventCompat.findPointerIndex(
- ev, mActivePointerId);
- final float x = MotionEventCompat.getX(ev, activePointerIndex);
- needsInvalidate |= performDrag(x);
- }
- break;
- case MotionEvent.ACTION_UP:
- if (mIsBeingDragged) {
- final VelocityTracker velocityTracker = mVelocityTracker;
- velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
- int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(
- velocityTracker, mActivePointerId);
- mPopulatePending = true;
- final int width = getClientWidth();
- final int scrollX = getScrollX();
- final ItemInfo ii = infoForCurrentScrollPosition();
- final int currentPage = ii.position;
- final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;
- final int activePointerIndex =
- MotionEventCompat.findPointerIndex(ev, mActivePointerId);
- final float x = MotionEventCompat.getX(ev, activePointerIndex);
- final int totalDelta = (int) (x - mInitialMotionX);
- int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
- totalDelta);
- setCurrentItemInternal(nextPage, true, true, initialVelocity);
- mActivePointerId = INVALID_POINTER;
- endDrag();
- needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
- }
- break;
- case MotionEvent.ACTION_CANCEL:
- if (mIsBeingDragged) {
- scrollToItem(mCurItem, true, 0, false);
- mActivePointerId = INVALID_POINTER;
- endDrag();
- needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
- }
- 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);
- mLastMotionX = MotionEventCompat.getX(ev,
- MotionEventCompat.findPointerIndex(ev, mActivePointerId));
- break;
- }
- if (needsInvalidate) {
- ViewCompat.postInvalidateOnAnimation(this);
- }
- return true;
- }
代码C:void android.support.v4.view.ViewPager.onSecondaryPointerUp(MotionEvent ev)
- private void onSecondaryPointerUp(MotionEvent ev) {
- final int pointerIndex = MotionEventCompat.getActionIndex(ev);
- final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
- if (pointerId == mActivePointerId) {
- // This was our active pointer going up. Choose a new
- // active pointer and adjust accordingly.
- final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
- mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex);
- mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
- if (mVelocityTracker != null) {
- mVelocityTracker.clear();
- }
- }
- }
总结
在这里就不想上篇文章那样分各种情况去讨论了。那样有些无聊。这里就重要点的说明一下我的理解,最后附一个我写的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
版权声明:本文博主原创文章。转载请注明出处。