突然遇到脑残的设计说viewpager的切换速度过快,要来个满动作,开始一听,这脑残设计,其实还是比较简单的
我们先来看段ViewPager的源码:
void initViewPager() { setWillNotDraw(false); setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); setFocusable(true); final Context context = getContext(); mScroller = new Scroller(context, sInterpolator); ..... }
来看一下源码中事件处理:<pre name="code" class="java"> @Override 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!"); resetTouch(); 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; }最终控制速度的体现都是mScroller
所以我们需要自定义Scroller
package com.example.viewpagerresearch; import android.content.Context; import android.view.animation.Interpolator; import android.widget.Scroller; /** * @author xuanyouwu * @email xuanyouwu@163.com * @time 2016-01-12 15:17 */ public class MyScroller extends Scroller { private long mDuration; public MyScroller(Context context) { super(context); } public MyScroller(Context context, Interpolator interpolator) { super(context, interpolator); } public MyScroller(Context context, Interpolator interpolator, boolean flywheel) { super(context, interpolator, flywheel); } public long getmDuration() { return mDuration; } public void setmDuration(long mDuration) { this.mDuration = mDuration; } @Override public void startScroll(int startX, int startY, int dx, int dy) { //super.startScroll(startX, startY, dx, dy); super.startScroll(startX, startY, dx, dy, this.getDuration()); } @Override public void startScroll(int startX, int startY, int dx, int dy, int duration) { // super.startScroll(startX, startY, dx, dy, duration); super.startScroll(startX, startY, dx, dy, this.getDuration()); } }
应用:
由于Viewpager中的mScroll是私有的,所以我们需要考虑反射
package com.example.viewpagerresearch; import android.support.v4.view.ViewPager; import android.view.animation.AccelerateInterpolator; import java.lang.reflect.Field; /** * @author xuanyouwu * @email xuanyouwu@163.com * @time 2016-01-12 16:54 */ public class ScrollUtils { /** * 例子 如匀加速 * * @param viewPager * @param speed */ public static void setViewPagerScrollSpeed(ViewPager viewPager, int speed) { try { Field field = ViewPager.class.getDeclaredField("mScroller"); field.setAccessible(true); // AccelerateInterpolator 是匀加速插值器 MyScroller viewPagerScroller = new MyScroller(viewPager.getContext(), new AccelerateInterpolator()); field.set(viewPager, viewPagerScroller); viewPagerScroller.setmDuration(speed); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }ok 调用ScrollUtils.setViewPagerScrollSpeed(pager,1000);