viewPager 是一個很常用的控件,應該完全掌握其各種用法,下面記錄一些常規代碼和自己遇到的問題。
viewPager 常規用法
MyAdapter adapter = new MyAdapter(this, mViewList);
mViewPager.setAdapter(adapter);
然後就是adapter 了, adapter 是關鍵,看看adapter
public class MyAdapter extends PagerAdapter {
private Context mContext;
private List<View> mViews;
public MyAdapter(Context context, List<View> viewList){
mViews = viewList;
mContext = context;
}
@Override
public int getCount() {
return mViews.size();
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object o) {
return view == o;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
// LayoutInflater inflater = LayoutInflater.from(mContext);
// View view = inflater.inflate(R.layout.page_adapter, container ,false);
// TextView textView = view.findViewById(R.id.tv);
// textView.setText(mViews.get(position));
container.addView(mViews.get(position));
// return super. instantiateItem(container, position) 這個也不能調用,否則會崩潰
return mViews.get(position);
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
// super.destroyItem(container, position, object); 這個super 不能調用 否則會崩潰
container.removeView((View) object);
}
}
這裏往adpter裏 添加了一些 view。在activity裏進行添加,
for (int i = 0; i < 5; i++) {
LinearLayout linearLayout = new LinearLayout(this);
TextView textView = new TextView(this);
textView.setText("tv" + i);
LinearLayout.LayoutParams layoutParams1 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
layoutParams1.gravity = Gravity.CENTER;
textView.setGravity(Gravity.CENTER);
linearLayout.setGravity(Gravity.CENTER);
textView.setLayoutParams(layoutParams1);
linearLayout.addView(textView);
mViewList.add(linearLayout);
}
這樣viewPager 就算是用上了。 後面可以作爲模板代碼,每次要用的話,直接粘貼複製。簡單分析一下:
在adapter中,必須重寫的方法是getCount 和 isViewFromObject ;然後 instantiateItem 和 destroyItem 分別是創建和銷燬 容器中的待裝對象,所以instantiateItem 方法返回的是object 對象,因爲container 事先也不知道要裝什麼。比如,這裏我裝的是view,不過更多的時候裝的是Fragment.
viewPager 用於Fragment
針對viewPager和Fragment的配合使用,官方退出了 FragmentPagerAdapter 和 FragmentStatePagerAdapter 這兩款 adapter ,同時,我們應該明白 Fragment 需要進行管理,這裏adapter 也承擔着管理fragment的功能。針對其區別和聯繫,可以參考:
https://developer.android.com/reference/android/support/v4/app/FragmentPagerAdapter
https://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter
主要來說就是一個少量的靜態頁面(變量進行緩存),一個是大量的動態頁面(其他不可見的頁面變量不進行緩存,直接銷燬)。
模板代碼:
public class BaseFragmentAdapter extends FragmentPagerAdapter {
private BaseFragment[] mFragmentList;
public BaseFragmentAdapter(FragmentManager fm, BaseFragment[] fragmentList) {
super(fm);
this.mFragmentList = fragmentList;
}
@Override
public Fragment getItem(int position) {
return mFragmentList[position];
}
@Override
public int getCount() {
if (mFragmentList == null) {
return 0;
}
return mFragmentList.length;
}
默認需要實現 getItem 和 getCount ,getItem 默認返回Fragment,所以我們必須提供Fragment的數據源,由此instantiateItem 方法可以不進行重寫,因爲instantiateItem方法本來就是創建對象的,而我們已經提供了對象,所以就不必再重寫這個方法了。
常見的坑
防止出現白屏
1. activity 包含多個Fragment (A,B....),然後某個Fragment(A) 又包含多個子Fragment(A1,A2....), 這時候 A 裏面獲取FragmentManager 要用 getChildFragmentManager() ;不能使用getSupportFragmentManager ,否則會出現白屏;
2. 設置預加載數量和禁止緩存
// 防止出現白屏 vpMain.setOffscreenPageLimit(fragment.size); vpMain.setSaveFromParentEnabled(false);
3. 考慮FragmentStatePageAdapter 替換FragmentPagerAdapter
其他的問題可以參考
1. 總結的很全面 https://guides.codepath.com/android/viewpager-with-fragmentpageradapter
2. FragmentPagerAdapter https://developer.android.com/reference/android/support/v4/app/FragmentPagerAdapter
3. https://stackoverflow.com/questions/22485899/fragment-isadded-returns-false-on-an-already-added-fragment 替換benginTrastion
4. https://stackoverflow.com/questions/7746652/fragment-in-viewpager-using-fragmentpageradapter-is-blank-the-second-time-it-is/22677595
5. https://blog.csdn.net/soha_dong/article/details/92659740
6. https://www.cnblogs.com/lianghui66/p/3607091.html
7. https://medium.com/inloopx/adventures-with-fragmentstatepageradapter-4f56a643f8e0