一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天 点击查看活动详情
【日期】: 2022/04/23
【问题】:ViewPager2 动态删除Fragment时,不论删除的是哪一个下标,总会删除最后一个
【如何发现】: 出现了问题,我们先去看源码:FragmentStateAdapter。java
/**
* 默认实现适用于不添加、移动或删除项的集合。
* <p>
* TODO(b/122670460): 重写这个方法的时候,要同时重写containsItem(long)
* <p>
* @param position Adapter position
* @return stable item id {@link RecyclerView.Adapter#hasStableIds()}
*/
@Override
public long getItemId(int position) {
return position;
}
/**
* 默认实现适用于不添加、移动或删除项的集合。
* <p>
* TODO(b/122670460): 重写这个方法的时候,要同时重写getItemId(int)
*/
public boolean containsItem(long itemId) {
return itemId >= 0 && itemId < getItemCount();
}
我们看到有这么两个方法,方法介绍这两个方法的默认实现只适用于不添加、移动或删除项的集合,但是我们需要进行添加或删除操作,那我们就需要重写这两个方法。
【如何修复】: 我们需要新建一个集成FragmentStateAdapter的类,并实现上面提到的两个方法: 先上完整代码:
class ViewPagerAdapter(
fm: FragmentManager,
lifecycle: Lifecycle,
private val fragments: MutableList<Fragment>
) : FragmentStateAdapter(fm, lifecycle) {
private val fragmentHashCodes = arrayListOf<Long>()
init {
for (fragment in fragments) {
fragmentHashCodes.add(fragment.hashCode().toLong())
}
}
override fun getItemCount(): Int {
return fragments.size
}
override fun createFragment(position: Int): Fragment {
return fragments[position]
}
fun removeFragment(position: Int){
fragments.removeAt(position)
fragmentHashCodes.removeAt(position)
notifyDataSetChanged()
}
fun addFragment(fragment: Fragment){
fragments.add(fragment)
fragmentHashCodes.add(fragment.hashCode().toLong())
notifyDataSetChanged()
}
override fun getItemId(position: Int): Long {
return fragments[position].hashCode().toLong()
}
override fun containsItem(itemId: Long): Boolean {
return fragmentHashCodes.contains(itemId)
}
}
我们定义两个数据源fragments: MutableList<Fragment> 和fragmentHashCodes: ArrayList<Long>
fragments: 用来存储上一个界面传递来的Fragment集合
mFragmentHashCodes: 用来存储每个Fragment对应的hashCode值,要注意,进行增删的时候,要和fragments保持一致
在Adapter创建的时候,我们初始化一个Long类型的空集合,并把fragments对应的hashCode值添加到fragmentHashCodes中。
private val fragmentHashCodes = arrayListOf<Long>()
init {
for (fragment in fragments) {
fragmentHashCodes.add(fragment.hashCode().toLong())
}
}
接下来我们需要添加一个添加方法:
fun addFragment(fragment: Fragment){
fragments.add(fragment)
fragmentHashCodes.add(fragment.hashCode().toLong())
notifyDataSetChanged()
}
添加Fragment的同时,也要把这个Fragment对应的hashCode添加到fragmentHashCodes中。
下面我们在添加一个删除方法,和添加方法同理:
fun removeFragment(position: Int){
fragments.removeAt(position)
fragmentHashCodes.removeAt(position)
notifyDataSetChanged()
}
然后我们在重写我们上面提到的两个重要的方法,也是我们解决这个问题的核心点:
override fun getItemId(position: Int): Long {
return fragments[position].hashCode().toLong()
}
override fun containsItem(itemId: Long): Boolean {
return fragmentHashCodes.contains(itemId)
}
最后我们在界面上调用:
val adapter = ViewPagerAdapter(supportFragmentManager, lifecycle, fragments)
binding.viewPager.adapter = adapter
binding.viewPager.isUserInputEnabled = false
binding.viewPager.offscreenPageLimit = fragments.size
binding.ivAdd.click {
adapter.addFragment(...)
binding.viewPager.setCurrentItem(fragments.size - 1, false)
binding.viewPager.offscreenPageLimit = fragments.size
}
问题解决!!!
【总结】:
遇到问题不可怕,当我们一时找不到解决方案的时候,我们可以先去看看官方源码,这些问题就迎刃而解了。
最后
感谢你看到最后, 最后再说两点~
①如果你持有不同的看法,欢迎你在文章下方进行留言、评论。
②如果对你有帮助,或者你认可的话,欢迎给个小点赞,支持一下~
我是沐小枫,一个热爱学习、热爱编程的山东人
(文章内容仅供学习参考, 如有侵权,非常抱歉,请立即联系作者删除。)