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

作者: 小怪兽打葫芦娃 | 来源:发表于2017-05-10 23:35 被阅读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切换页面,效果如下:


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

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

    相关文章

      网友评论

      • _那个人:如果将 ViewPager的宽度设置小一点 漏出左右的pager 这样切换的时候还是会出现短暂的白屏
      • d8184ca3c970:不经过中间界面了,可是滑动的动画也没了,怎么搞
      • hyyly:滑动的时候,有阴影效果,怎么做的呢?😂
      • 四单老师:问一下,setCurrentItem这个方法往回设置的时候,超过缓存的边界,界面会卡死ANR,这个如何解决啊?
      • mundane:我发现使用ViewPager.setCurrentItem(item, true)就不会出现空白页面(第二个参数设置为true)。不明白这是什么原因, 这篇博客中貌似也并没有提到bug产生的原因。
      • sankemao:这个bug在自定义轮播图的时候遇过
      • DreamArea:这个很好。。。:grin:
      • f5d6ee5118da:老师这个反射这块在做啥不太懂
        f5d6ee5118da: @马伟奇 谢谢老师早点休息
        小怪兽打葫芦娃:@第三天_5c80 通过暴力反射可以拿到私有属性,然后可以动态控制滑动的值
      • 0445981d6022:马老师还在黑马么?
        小怪兽打葫芦娃:@谢伊帕特里克寇马克 还在的。。:smile:

      本文标题:Android面试题-终极解决ViewPager.setCurr

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