ViewPager2动态添加删除Fragment
需求
未登录显示 B,C 两个Tab
登录后显示 A,B,C三个Tab
其实不一定会是 ABC这个顺序,BAC,BCA,也是可能的
单纯的修改getItemCount()这个方法的返回值,比如未登录返回2,登录后返回3,然后调用viewPager.adapter!!.notifyDataSetChanged() 是不能保证Fragment正确显示的,如果正确显示了想必你们也不会搜到这篇博客了。
直接依靠position是无法做到我们的需求的,就拿未登录显示BC,登录后显示ABC这个需求来说
在未登录的时候position返回为 0,1,登录后返回为0,1,2。在createFragment这个方法中如何在position=0时未登录显示B,登录显示A;position=1时未登录显示C,登录显示B;position=2时登录显示C呢
我是这么做得,登录后和未登录对应着mIds[0,1,2],mIds1[1,2],这样登录的position0的id=0,未登录的position0的id=1。
override fun createFragment(position: Int): Fragment {
val id: Long
if (DataRepo.isLogin()) {
id = mIds[position] //[0,1,2]
} else {
id = mIds1[position]//[1,2]
}
when (id) {
0L -> {
//加载A
}
1L -> {
//加载B
}
2L -> {
//加载C
}
}
}
但仅仅这样做还不够哦,因为你会发现Fragment还是没有正确显示,因为在FragmentStateAdapter中维护着一个稀疏数组LongSparseArray缓存已加载的Fragment,他通过getItemId(position)来作为索引获取Fragment,没有找到Framgent就会调用createFragment(position),这个getItemId默认返回position,这下明白了吧,我们未登录和已登录的Tab对应的position是不同的。
private void ensureFragment(int position) {
long itemId = getItemId(position);
if (!mFragments.containsKey(itemId)) {
// TODO(133419201): check if a Fragment provided here is a new Fragment
Fragment newFragment = createFragment(position);
newFragment.setInitialSavedState(mSavedStates.get(itemId));
mFragments.put(itemId, newFragment);
}
}
所以还需要重写getItemId和containsItem两个方法
override fun getItemId(position: Int): Long {
if (DataRepo.isLogin()) {
return mIds[position]
} else {
return mIds1[position]
}
}
override fun containsItem(itemId: Long): Boolean {
if (DataRepo.isLogin()) {
return mIds.contains(itemId)
} else {
return mIds1.contains(itemId)
}
}
这样一来,未登录的时候position =0,系统调用ensureFragment(0),然后创建B,对应的itemId=1,加入到稀疏数组mFragments中,登录后position=0,系统调用ensureFragment(0),然后创建A,对应的itemId=0,加入到稀疏数组mFragments中,再调用ensureFragment(1),在稀疏数组mFragments查找到B。
简单来说:
未登录Tab[B,C],对应的position[0,1],对应的id[1,2]
登录后Tab[A,B,C],对应的position[0,1,2],对应的id[0,1,2]
到此为止结束。。。。。但其实我觉得没必要维护两个ids列表,直接通过tabs[position].hashCode().toLong()这种方式去做可能更简单。
再说一下其他的,如何获取到VIewPager2中的Framgent
方法有两个
1.通过f+id查找,因为内部添加的时候就是这么添加的,但这种不太保险,万一以后规则变了就gg了,但可能性不大
childFragmentManager.findFragmentByTag(“f” + id.toInt())
mFragmentManager.beginTransaction()
.add(fragment, "f" + holder.getItemId())
.setMaxLifecycle(fragment, STARTED)
.commitNow();
2.直接通过反射拿到FragmentStateAdapter中维护的稀疏数组mFragments