ViewPager smoothScroll 速度控制

作者: 王尼小老板 | 来源:发表于2016-10-26 15:56 被阅读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) 的时候应该就可以看到缓慢滑动的效果了。

相关文章

网友评论

  • ff334c46f922:完美运行,速度改为1200差不多了。谢谢。
  • 9df2a6e99159:但是这样如果手动滑的话速度也会变,甚至会出现果冻一样的卡顿感,你的没有么,怎么解决啊
    780320635971:把插值器去掉。一切就OK。
  • 那就走吧玉二:楼主,我跟你一样通过反射设置滑动的时间,但是有时候会出现viewpager页面显示异常的情况:joy:
    王尼小老板:@e10640117 具体什么异常呢,我没有遇到
    那就走吧玉二:@琚涛 对呀,调了setCurrentItem()方法之后,楼主你遇到了吗
    王尼小老板:@e10640117 你也是修改的mScroller吗
  • 英勇青铜5:学习:smile:
    王尼小老板:@英勇青铜5 :+1:

本文标题:ViewPager smoothScroll 速度控制

本文链接:https://www.haomeiwen.com/subject/iyoduttx.html