zoukankan      html  css  js  c++  java
  • 菜鸟进阶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.   
    8.         final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;  
    9.   
    10.         // Always take care of the touch gesture being complete.  
    11.         if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {  
    12.             // Release the drag.  
    13.             if (DEBUG) Log.v(TAG, "Intercept done!");  
    14.             mIsBeingDragged = false;  
    15.             mIsUnableToDrag = false;  
    16.             mActivePointerId = INVALID_POINTER;  
    17.             if (mVelocityTracker != null) {  
    18.                 mVelocityTracker.recycle();  
    19.                 mVelocityTracker = null;  
    20.             }  
    21.             return false;  
    22.         }  
    23.   
    24.         // Nothing more to do here if we have decided whether or not we  
    25.         // are dragging.  
    26.         if (action != MotionEvent.ACTION_DOWN) {  
    27.             if (mIsBeingDragged) {  
    28.                 if (DEBUG) Log.v(TAG, "Intercept returning true!");  
    29.                 return true;  
    30.             }  
    31.             if (mIsUnableToDrag) {  
    32.                 if (DEBUG) Log.v(TAG, "Intercept returning false!");  
    33.                 return false;  
    34.             }  
    35.         }  
    36.   
    37.         switch (action) {  
    38.             case MotionEvent.ACTION_MOVE: {  
    39.                 /* 
    40.                  * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check 
    41.                  * whether the user has moved far enough from his original down touch. 
    42.                  */  
    43.   
    44.                 /* 
    45.                 * Locally do absolute value. mLastMotionY is set to the y value 
    46.                 * of the down event. 
    47.                 */  
    48.                 final int activePointerId = mActivePointerId;  
    49.                 if (activePointerId == INVALID_POINTER) {  
    50.                     // If we don't have a valid id, the touch down wasn't on content.  
    51.                     break;  
    52.                 }  
    53.   
    54.                 final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId);  
    55.                 final float x = MotionEventCompat.getX(ev, pointerIndex);  
    56.                 final float dx = x - mLastMotionX;  
    57.                 final float xDiff = Math.abs(dx);  
    58.                 final float y = MotionEventCompat.getY(ev, pointerIndex);  
    59.                 final float yDiff = Math.abs(y - mInitialMotionY);  
    60.                 if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);  
    61.   
    62.                 if (dx != 0 && !isGutterDrag(mLastMotionX, dx) &&  
    63.                         canScroll(thisfalse, (int) dx, (int) x, (int) y)) {  
    64.                     // Nested view has scrollable area under this point. Let it be handled there.  
    65.                     mLastMotionX = x;  
    66.                     mLastMotionY = y;  
    67.                     mIsUnableToDrag = true;  
    68.                     return false;  
    69.                 }  
    70.                 if (xDiff > mTouchSlop && xDiff * 0.5f > yDiff) {  
    71.                     if (DEBUG) Log.v(TAG, "Starting drag!");  
    72.                     mIsBeingDragged = true;  
    73.                     requestParentDisallowInterceptTouchEvent(true);  
    74.                     setScrollState(SCROLL_STATE_DRAGGING);  
    75.                     mLastMotionX = dx > 0 ? mInitialMotionX + mTouchSlop :  
    76.                             mInitialMotionX - mTouchSlop;  
    77.                     mLastMotionY = y;  
    78.                     setScrollingCacheEnabled(true);  
    79.                 } else if (yDiff > mTouchSlop) {  
    80.                     // The finger has moved enough in the vertical  
    81.                     // direction to be counted as a drag...  abort  
    82.                     // any attempt to drag horizontally, to work correctly  
    83.                     // with children that have scrolling containers.  
    84.                     if (DEBUG) Log.v(TAG, "Starting unable to drag!");  
    85.                     mIsUnableToDrag = true;  
    86.                 }  
    87.                 if (mIsBeingDragged) {  
    88.                     // Scroll to follow the motion event  
    89.                     if (performDrag(x)) {  
    90.                         ViewCompat.postInvalidateOnAnimation(this);  
    91.                     }  
    92.                 }  
    93.                 break;  
    94.             }  
    95.   
    96.             case MotionEvent.ACTION_DOWN: {  
    97.                 /* 
    98.                  * Remember location of down touch. 
    99.                  * ACTION_DOWN always refers to pointer index 0. 
    100.                  */  
    101.                 mLastMotionX = mInitialMotionX = ev.getX();  
    102.                 mLastMotionY = mInitialMotionY = ev.getY();  
    103.                 mActivePointerId = MotionEventCompat.getPointerId(ev, 0);  
    104.                 mIsUnableToDrag = false;  
    105.   
    106.                 mScroller.computeScrollOffset();  
    107.                 if (mScrollState == SCROLL_STATE_SETTLING &&  
    108.                         Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) {  
    109.                     // Let the user 'catch' the pager as it animates.  
    110.                     mScroller.abortAnimation();  
    111.                     mPopulatePending = false;  
    112.                     populate();  
    113.                     mIsBeingDragged = true;  
    114.                     requestParentDisallowInterceptTouchEvent(true);  
    115.                     setScrollState(SCROLL_STATE_DRAGGING);  
    116.                 } else {  
    117.                     completeScroll(false);  
    118.                     mIsBeingDragged = false;  
    119.                 }  
    120.   
    121.                 if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY  
    122.                         + " mIsBeingDragged=" + mIsBeingDragged  
    123.                         + "mIsUnableToDrag=" + mIsUnableToDrag);  
    124.                 break;  
    125.             }  
    126.   
    127.             case MotionEventCompat.ACTION_POINTER_UP:  
    128.                 onSecondaryPointerUp(ev);  
    129.                 break;  
    130.         }  
    131.   
    132.         if (mVelocityTracker == null) {  
    133.             mVelocityTracker = VelocityTracker.obtain();  
    134.         }  
    135.         mVelocityTracker.addMovement(ev);  
    136.   
    137.         /* 
    138.          * The only time we want to intercept motion events is if we are in the 
    139.          * drag mode. 
    140.          */  
    141.         return mIsBeingDragged;  
    142.     }  
    代码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.   
    9.         if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {  
    10.             // Don't handle edge touches immediately -- they may actually belong to one of our  
    11.             // descendants.  
    12.             return false;  
    13.         }  
    14.   
    15.         if (mAdapter == null || mAdapter.getCount() == 0) {  
    16.             // Nothing to present or scroll; nothing to touch.  
    17.             return false;  
    18.         }  
    19.   
    20.         if (mVelocityTracker == null) {  
    21.             mVelocityTracker = VelocityTracker.obtain();  
    22.         }  
    23.         mVelocityTracker.addMovement(ev);  
    24.   
    25.         final int action = ev.getAction();  
    26.         boolean needsInvalidate = false;  
    27.   
    28.         switch (action & MotionEventCompat.ACTION_MASK) {  
    29.             case MotionEvent.ACTION_DOWN: {  
    30.                 mScroller.abortAnimation();  
    31.                 mPopulatePending = false;  
    32.                 populate();  
    33.   
    34.                 // Remember where the motion event started  
    35.                 mLastMotionX = mInitialMotionX = ev.getX();  
    36.                 mLastMotionY = mInitialMotionY = ev.getY();  
    37.                 mActivePointerId = MotionEventCompat.getPointerId(ev, 0);  
    38.                 break;  
    39.             }  
    40.             case MotionEvent.ACTION_MOVE:  
    41.                 if (!mIsBeingDragged) {  
    42.                     final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);  
    43.                     final float x = MotionEventCompat.getX(ev, pointerIndex);  
    44.                     final float xDiff = Math.abs(x - mLastMotionX);  
    45.                     final float y = MotionEventCompat.getY(ev, pointerIndex);  
    46.                     final float yDiff = Math.abs(y - mLastMotionY);  
    47.                     if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);  
    48.                     if (xDiff > mTouchSlop && xDiff > yDiff) {  
    49.                         if (DEBUG) Log.v(TAG, "Starting drag!");  
    50.                         mIsBeingDragged = true;  
    51.                         requestParentDisallowInterceptTouchEvent(true);  
    52.                         mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop :  
    53.                                 mInitialMotionX - mTouchSlop;  
    54.                         mLastMotionY = y;  
    55.                         setScrollState(SCROLL_STATE_DRAGGING);  
    56.                         setScrollingCacheEnabled(true);  
    57.   
    58.                         // Disallow Parent Intercept, just in case  
    59.                         ViewParent parent = getParent();  
    60.                         if (parent != null) {  
    61.                             parent.requestDisallowInterceptTouchEvent(true);  
    62.                         }  
    63.                     }  
    64.                 }  
    65.                 // Not else! Note that mIsBeingDragged can be set above.  
    66.                 if (mIsBeingDragged) {  
    67.                     // Scroll to follow the motion event  
    68.                     final int activePointerIndex = MotionEventCompat.findPointerIndex(  
    69.                             ev, mActivePointerId);  
    70.                     final float x = MotionEventCompat.getX(ev, activePointerIndex);  
    71.                     needsInvalidate |= performDrag(x);  
    72.                 }  
    73.                 break;  
    74.             case MotionEvent.ACTION_UP:  
    75.                 if (mIsBeingDragged) {  
    76.                     final VelocityTracker velocityTracker = mVelocityTracker;  
    77.                     velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);  
    78.                     int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(  
    79.                             velocityTracker, mActivePointerId);  
    80.                     mPopulatePending = true;  
    81.                     final int width = getClientWidth();  
    82.                     final int scrollX = getScrollX();  
    83.                     final ItemInfo ii = infoForCurrentScrollPosition();  
    84.                     final int currentPage = ii.position;  
    85.                     final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;  
    86.                     final int activePointerIndex =  
    87.                             MotionEventCompat.findPointerIndex(ev, mActivePointerId);  
    88.                     final float x = MotionEventCompat.getX(ev, activePointerIndex);  
    89.                     final int totalDelta = (int) (x - mInitialMotionX);  
    90.                     int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,  
    91.                             totalDelta);  
    92.                     setCurrentItemInternal(nextPage, truetrue, initialVelocity);  
    93.   
    94.                     mActivePointerId = INVALID_POINTER;  
    95.                     endDrag();  
    96.                     needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();  
    97.                 }  
    98.                 break;  
    99.             case MotionEvent.ACTION_CANCEL:  
    100.                 if (mIsBeingDragged) {  
    101.                     scrollToItem(mCurItem, true0false);  
    102.                     mActivePointerId = INVALID_POINTER;  
    103.                     endDrag();  
    104.                     needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();  
    105.                 }  
    106.                 break;  
    107.             case MotionEventCompat.ACTION_POINTER_DOWN: {  
    108.                 final int index = MotionEventCompat.getActionIndex(ev);  
    109.                 final float x = MotionEventCompat.getX(ev, index);  
    110.                 mLastMotionX = x;  
    111.                 mActivePointerId = MotionEventCompat.getPointerId(ev, index);  
    112.                 break;  
    113.             }  
    114.             case MotionEventCompat.ACTION_POINTER_UP:  
    115.                 onSecondaryPointerUp(ev);  
    116.                 mLastMotionX = MotionEventCompat.getX(ev,  
    117.                         MotionEventCompat.findPointerIndex(ev, mActivePointerId));  
    118.                 break;  
    119.         }  
    120.         if (needsInvalidate) {  
    121.             ViewCompat.postInvalidateOnAnimation(this);  
    122.         }  
    123.         return true;  
    124.     }  
    代码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

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

  • 相关阅读:
    由AbstractQueuedSynchronizer和ReentrantLock来看模版方法模式
    Java并发编程-CAS
    Java并发编程-volatile
    Java并发编程-synchronized
    学习几个协议
    邻接矩阵存储简单路径(1070)
    输出利用先序遍历创建的二叉树的层次遍历序列(0980)
    中缀表达式转换为后缀表达式(1042)
    特定字符序列的判断(1028)
    舞伴问题(1027)
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4758349.html
Copyright © 2011-2022 走看看