Android面试题-终极解决ViewPager.setCurrentItem中间很多页面切换方案

来源:互联网 发布:tm域名商标骗局 编辑:程序博客网 时间:2024/06/05 02:40

本文配套视频

  • ViewPager.setCurrentItem的bug演示一
  • ViewPager.setCurrentItem解决方案二

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

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

ViewPager.setCurrentItem(position,false);

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

从第一题点击切换到第十八题,你会发现页面显示空白,如果从第十个页面切换到第十五个页面没事,平时大家估计没有发现这个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)动态判断页面是否需要滑动,如果不需要滑动,设置滑动时间为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)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);        }    }}

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

  • 欢迎关注微信公众号,长期推荐技术文章和技术视频

  • 微信公众号名称:Android干货程序员

1 0
原创粉丝点击