尊重他人劳动成果,转载请说明出处: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) {
-
-
-
-
-
-
-
final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
-
-
-
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
-
-
if (DEBUG) Log.v(TAG, "Intercept done!");
-
mIsBeingDragged = false;
-
mIsUnableToDrag = false;
-
mActivePointerId = INVALID_POINTER;
-
if (mVelocityTracker != null) {
-
mVelocityTracker.recycle();
-
mVelocityTracker = null;
-
}
-
return false;
-
}
-
-
-
-
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: {
-
-
-
-
-
-
-
-
-
-
final int activePointerId = mActivePointerId;
-
if (activePointerId == INVALID_POINTER) {
-
-
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)) {
-
-
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) {
-
-
-
-
-
if (DEBUG) Log.v(TAG, "Starting unable to drag!");
-
mIsUnableToDrag = true;
-
}
-
if (mIsBeingDragged) {
-
-
if (performDrag(x)) {
-
ViewCompat.postInvalidateOnAnimation(this);
-
}
-
}
-
break;
-
}
-
-
case MotionEvent.ACTION_DOWN: {
-
-
-
-
-
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) {
-
-
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);
-
-
-
-
-
-
return mIsBeingDragged;
-
}
代码B:boolean android.support.v4.view.ViewPager.onTouchEvent(MotionEvent ev)
-
public boolean onTouchEvent(MotionEvent ev) {
-
if (mFakeDragging) {
-
-
-
-
return true;
-
}
-
-
if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
-
-
-
return false;
-
}
-
-
if (mAdapter == null || mAdapter.getCount() == 0) {
-
-
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();
-
-
-
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);
-
-
-
ViewParent parent = getParent();
-
if (parent != null) {
-
parent.requestDisallowInterceptTouchEvent(true);
-
}
-
}
-
}
-
-
if (mIsBeingDragged) {
-
-
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) {
-
-
-
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