android系统控件Android所有文章都配视频讲解天花板谈Android开发

Android面试题-终极解决ViewPager.setCurr

2017-05-10  本文已影响6623人  小怪兽打葫芦娃

Android程序员面试宝典

自定义控件

联网

工具

数据库

源码分析相关面试题

Activity相关面试题

Service相关面试题

与XMPP相关面试题

与性能优化相关面试题

与登录相关面试题

与开发相关面试题

与人事相关面试题

本文配套视频

今天做项目用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切换页面,效果如下:


上一篇下一篇

猜你喜欢

热点阅读