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) 的时候应该就可以看到缓慢滑动的效果了。

    相关文章

      网友评论

      本文标题:ViewPager smoothScroll 速度控制

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