Android面試題-終極解決ViewPager.setCurrentItem中間頁面過多解決方案

weixin_34402408發表於2017-05-10

Android程式設計師面試寶典

自定義控制元件

聯網

工具

資料庫

原始碼分析相關面試題

Activity相關面試題

Service相關面試題

與XMPP相關面試題

與效能優化相關面試題

與登入相關面試題

與開發相關面試題

與人事相關面試題

本文配套視訊

今天做專案用ViewPager.setCurrentItem 方法,如果兩個頁面相聚比較遠,就會閃瞎我的鈦合金雙眼,中間切換大概20個頁面,如下所示:


4037105-bab7127dbfb0d444

setCurrentItem第二個引數設定false,四不四很簡單,直接使用如下程式碼:

ViewPager.setCurrentItem(position,false);

很不幸的是,使用上面的程式碼會出現如下效果,扎心了老鐵:


4037105-5dc7bf8e931596ce

從第一題點選切換到第十八題,你會發現頁面顯示空白,如果從第十個頁面切換到第十五個頁面沒事,平時大家估計沒有發現這個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切換頁面,效果如下:


4037105-b2f5486c91c65eae
  • 歡迎關注微信公眾號,長期推薦技術文章和技術視訊

  • 微信公眾號名稱:Android乾貨程式設計師

4037105-8f737b5104dd0b5d.png

相關文章