ViewPager2 无法动态添加删除片段
Posted
技术标签:
【中文标题】ViewPager2 无法动态添加删除片段【英文标题】:ViewPager2 not able to dynamically add remove fragment 【发布时间】:2020-08-07 21:31:45 【问题描述】:在索引处删除/添加片段会导致 Viewpager2 出现意外行为。 ViewPager
无法做到这一点,但预计可以与 Viewpager2
一起使用。它会导致重复片段和不同步TabLayout
。
Here is a demo project 重现了这个问题。有一个切换按钮可以删除片段并将其重新附加到特定索引处。在这种情况下,附加的片段应该是绿色的,但它是蓝色的,并且不知何故有 2 个蓝色片段。
这是我的适配器的外观
class ViewPager2Adapter(activity: FragmentActivity) : FragmentStateAdapter(activity)
val fragmentList: MutableList<FragmentName> = mutableListOf()
override fun getItemCount(): Int
return fragmentList.size
override fun createFragment(position: Int): Fragment
return when (fragmentList[position])
FragmentName.WHITE -> WhiteFragment()
FragmentName.RED -> RedFragment()
FragmentName.GREEN -> GreenFragment()
FragmentName.BLUE -> BlueFragment()
fun add(fragment: FragmentName)
fragmentList.add(fragment)
notifyDataSetChanged()
fun add(index: Int, fragment: FragmentName)
fragmentList.add(index, fragment)
notifyDataSetChanged()
fun remove(index: Int)
fragmentList.removeAt(index)
notifyDataSetChanged()
fun remove(name: FragmentName)
fragmentList.remove(name)
notifyDataSetChanged()
enum class FragmentName
WHITE,
RED,
GREEN,
BLUE
我也向谷歌提交了bug
【问题讨论】:
【参考方案1】:事实证明,如果您在 ViewPager2
中使用 mutable
集合,则需要覆盖这两个方法
override fun getItemId(position: Int): Long
return fragmentList[position].ordinal.toLong()
override fun containsItem(itemId: Long): Boolean
val fragment = FragmentName.values()[itemId.toInt()]
return fragmentList.contains(fragment)
在我当前的适配器中添加这两个可以解决问题
【讨论】:
救世主!过去 2 小时一直在尝试解决此问题 您是否遇到过因此更改而无法在方向/配置更改时重新附加片段的问题? @ScruffyFox 我不记得测试过配置更改场景,但这应该不是问题,因为重新创建了适配器并且所有片段都随之重新创建。确保始终在createFragment
中创建新片段。
当我从 ViewPager 中删除片段时,关联的 ViewModel 为空(与片段相同的生命周期)并且无法正确更新。您如何处理这种情况?
也许将 ViewModel 与父活动相关联?另外:developer.android.com/topic/libraries/architecture/…【参考方案2】:
这对我来说很奇怪
getItemId()
containsItem()
在使用 3 种 Fragment 时只会给出undesirable behavior。
最后我只需要一个像这样的简单FragmentStateAdapter
类
class AppFragmentAdapter(private val fragmentList: MutableList<Pair<String, Fragment>>, fragment: Fragment) : FragmentStateAdapter(fragment)
// private var pageIds = fragmentList.map fragmentList.hashCode().toLong()
override fun getItemCount(): Int = fragmentList.size
override fun createFragment(position: Int): Fragment
return fragmentList[position].second
// override fun getItemId(position: Int): Long = pageIds[position] // Make sure notifyDataSetChanged() works
// override fun containsItem(itemId: Long): Boolean = pageIds.contains(itemId)
fun getFragmentName(position: Int) = fragmentList[position].first
fun addFragment(fragment: Pair<String, Fragment>)
fragmentList.add(fragment)
notifyDataSetChanged()
fun removeFragment(position: Int)
fragmentList.removeAt(position)
notifyDataSetChanged()
太糟糕了,我正在寻找一个关于如何使 ViewPager2 动态化的直接答案,而没有先尝试我能想到的最简单的方法。许多人在这里回答指出,在 ViewPager2 上添加或删除 Fragment 时需要覆盖 getItemId()
和 containsItem()
,这让人头疼了将近 2 天。感觉被背叛了。
【讨论】:
以上是关于ViewPager2 无法动态添加删除片段的主要内容,如果未能解决你的问题,请参考以下文章
使用 FragmentStatePagerAdapter 在 ViewPager 的两侧动态添加片段
删除 viewPager2 中的片段使用 FragmentStateAdapter,但仍显示