viewpager管理fragment 如果一次性跳過的界面過多 會出現加載慢的問題 或者切換動畫閃屏的問題
一下是摘取馬偉奇老師簡書的代碼:
今天做項目用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切換頁面。