Android开发Android知识Android技术知识

ViewPager smoothScroll 速度控制

2016-10-26  本文已影响2595人  王尼小老板

问题

大家都知道 ViewPager 可以通过 mViewPager.setCurrentItem(index, true) 来始切换动画时进行平缓的滑动,但是如果我们的需求是控制滑动时间的话,会发现 ViewPager 好像并没有提供这一个方法。我们可以查看ViewPager 的源码:

    public void setCurrentItem(int item, boolean smoothScroll) {
    mPopulatePending = false;
    setCurrentItemInternal(item, smoothScroll, false);
    }

发现 setCurrentItem 走的是一个 setCurrentItemInternal(item, smoothScroll, false) 方法

void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {
    setCurrentItemInternal(item, smoothScroll, always, 0);
}

而这个方法所调用的 void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) 方法貌似是可以指定速度的,但是先别高兴的太早,这个方法居然不是 public 的。。也就是说我们调用不了。但是这也难不倒我们,用反射就轻松解决了。 有兴趣你可以用反射调用这个方法试试看,反正我是试过了,速度好像并没有什么明显的变化,再仔细看了看源码,我们发现最终走的 smoothScrollTo 方法中有一句

duration = Math.min(duration, MAX_SETTLE_DURATION)

然而我们发现 ViewPager 中有一个常量 private static final int MAX_SETTLE_DURATION = 600; // ms

也就是说 duration 无论如何都不会超过 600ms 的,那我们偏要大于 600ms 呢?

毕竟道高一尺魔高一丈,我们发现有了 duration 后,会调用 mScroller.startScroll(sx, sy, dx, dy, duration) 方法,终究还是要走 mScroller 的,那我们用反射修改 mScroller不就行了吗?

效果前后展示

有没有感觉太快了呢?


没有减速.gif

这样是不是好一点了呢


已经减速.gif

解决方案

重写一个 Scroller 类:

/**
 * 利用这个类来修正ViewPager的滑动速度
 * 我们重写 startScroll方法,忽略传过来的 duration 属性
 * 而是采用我们自己设置的时间
 */
public class FixedSpeedScroller extends Scroller {

  public int mDuration=1500;
  public FixedSpeedScroller(Context context) {
    super(context);
  }

  public FixedSpeedScroller(Context context, Interpolator interpolator) {
    super(context, interpolator);
  }

  public FixedSpeedScroller(Context context, Interpolator interpolator, boolean flywheel) {
    super(context, interpolator, flywheel);
  }

  @Override public void startScroll(int startX, int startY, int dx, int dy) {
    startScroll(startX,startY,dx,dy,mDuration);
  }

  @Override public void startScroll(int startX, int startY, int dx, int dy, int duration) {
    //管你 ViewPager 传来什么时间,我完全不鸟你
    super.startScroll(startX, startY, dx, dy, mDuration);
  }

  public int getmDuration() {
    return mDuration;
  }

  public void setmDuration(int duration) {
    mDuration = duration;
  }
}

利用反射把我们的 FixedSpeedScroller 类设置给 ViewPager

/**
 * 通过反射来修改 ViewPager的mScroller属性
 */
try {
  Class clazz=Class.forName("android.support.v4.view.ViewPager");
  Field f=clazz.getDeclaredField("mScroller");
  FixedSpeedScroller fixedSpeedScroller=new FixedSpeedScroller(this,new LinearOutSlowInInterpolator());
  fixedSpeedScroller.setmDuration(2000);
  f.setAccessible(true);
  f.set(mViewPager,fixedSpeedScroller);
} catch (Exception e) {
  e.printStackTrace();
}

这个时候再设置 mViewPager.setCurrentItem(index, true) 的时候应该就可以看到缓慢滑动的效果了。

上一篇下一篇

猜你喜欢

热点阅读