解决ViewPager.setCurrentItem中间很多页面切换方案

本文配套视频

今天做项目用ViewPager.setCurrentItem 方法,如果两个页面相聚比较远,就会闪瞎我的钛合金双眼,中间切换大概20个页面,如下所示: 

setCurrentItem第二个参数设置false,四不四很简单,直接使用如下代码:

ViewPager.setCurrentItem(position,false);
  • 1

很不幸的是,使用上面的代码会出现如下效果,扎心了老铁: 

从第一题点击切换到第十八题,你会发现页面显示空白,如果从第十个页面切换到第十五个页面没事,平时大家估计没有发现这个bug,一般我们使用ViewPager都是底下5个tab页面,从第一个切换到第五个没事,之前我也以为把第二个参数设置false就行,今天才发现,原来如果当页面比较少的时候,大概十个以内,一般没有问题,如果超过十个页面切换就会出现空白,加载不了数据,扎心了,提出解决方案吧,ViewPager滑动使用的是Scroll,咱们把Scroll的滑动时间duration 设置为0就行。

自定义一个Scroll类,用于控制ViewPager滑动速度:

public  class MScroller extends Scroller {

   private static final Interpolator sInterpolator = new Interpolator() {
   public float getInterpolation(float t) {
            t -= 1.0f;
            return t * t * t * t * t + 1.0f;
        }
    };


  public boolean noDuration;

  public void setNoDuration(boolean noDuration) {
        this.noDuration = noDuration;
    }

  public MScroller(Context context) {
        this(context,sInterpolator);
  }

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

    @Override
  public void startScroll(int startX, int startY, int dx, int dy, int duration) {
        if(noDuration)
            //界面滑动不需要时间间隔
            super.startScroll(startX, startY, dx, dy, 0);
        else
            super.startScroll(startX, startY, dx, dy,duration);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

上面代码可知:

1)动态判断页面是否需要滑动,如果不需要滑动,设置滑动时间为0;

为方便使用,定义一个辅助类

public class ViewPageHelper {
    ViewPager viewPager;

    MScroller scroller;

    public ViewPageHelper(ViewPager viewPager) {
        this.viewPager = viewPager;
        init();
    }

    public void setCurrentItem(int item){
        setCurrentItem(item,true);
    }

    public MScroller getScroller() {
        return scroller;
    }


    public void setCurrentItem(int item, boolean somoth){
        int current=viewPager.getCurrentItem();
        //如果页面相隔大于1,就设置页面切换的动画的时间为0
        if(Math.abs(current-item)>1){
            scroller.setNoDuration(true);
            viewPager.setCurrentItem(item,somoth);
            scroller.setNoDuration(false);
        }else{
            scroller.setNoDuration(false);
            viewPager.setCurrentItem(item,somoth);
        }
    }

    private void init(){
        scroller=new MScroller(viewPager.getContext());
        Class<ViewPager>cl=ViewPager.class;
        try {
            Field field=cl.getDeclaredField("mScroller");
            field.setAccessible(true);
            //利用反射设置mScroller域为自己定义的MScroller
            field.set(viewPager,scroller);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }catch (IllegalAccessException e){
            e.printStackTrace();
        }
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

由上面代码可知:

1)Math.abs(current-item)>1 ,通过数学函数判断页面相隔大于1,就设置页面切换的动画的时间为0。

2)这样每次设置页面的时候,通过 helper 就可以自动选择是否有时间间隔了。

3)但是这样有点麻烦,每次还要手动改,而且使用TabLayout或者ViewPagerIndicator的话,它会自动调用ViewPager的方法,无法使用Helper,所以可以采用自定一个ViewPager,代码如下:

public class SuperViewPager extends ViewPager {


    private ViewPageHelper helper;

    public SuperViewPager(Context context) {
        this(context,null);
    }

    public SuperViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        helper=new ViewPageHelper(this);

   }

    @Override
    public void setCurrentItem(int item) {
        setCurrentItem(item,true);
    }

    @Override
    public void setCurrentItem(int item, boolean smoothScroll) {
        MScroller scroller=helper.getScroller();
        if(Math.abs(getCurrentItem()-item)>1){
            scroller.setNoDuration(true);
            super.setCurrentItem(item, smoothScroll);
            scroller.setNoDuration(false);
        }else{
            scroller.setNoDuration(false);
            super.setCurrentItem(item, smoothScroll);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

至此完美解决了,ViewPager.setCurrentItem切换页面,效果如下: 

猜你喜欢

转载自blog.csdn.net/lyy666888/article/details/80089104
今日推荐