【问题标题】:ViewPager2 not able to dynamically add remove fragmentViewPager2 无法动态添加删除片段
【发布时间】:2020-08-07 21:31:45
【问题描述】:

在索引处删除/添加片段会导致 Viewpager2 出现意外行为。 ViewPager 无法做到这一点,但预计可以与 Viewpager2 一起使用。它会导致重复片段和不同步TabLayoutHere 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

【问题讨论】:

    标签: android android-fragments android-viewpager android-viewpager2


    【解决方案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 天。感觉被背叛了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-31
      • 2013-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-18
      相关资源
      最近更新 更多