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