使用FragmentStateAdapter在ViewPager2中删除片段,但仍然显示。

33

我有一个 viewPager2 和 FragmentStateAdapter,里面有 Fragment1、Fragment2、Fragment3、Fragment4。在 Fragment2 中,我想要移除 Fragment3,并在 Fragment2 后显示 Fragment4。

问题是它总是显示 Fragment3 的内容,调试显示 Fragment3 已经被移除了,但是显示的页面仍然有 Fragment3 的内容。

适配器:

class TipsAdapter(
private val items: MutableList<TripPage>,
context: FragmentActivity
) : FragmentStateAdapter(context) {

private val fragmentFactory = context.supportFragmentManager.fragmentFactory
private val classLoader = context.classLoader

override fun getItemCount(): Int = items.size

override fun createFragment(position: Int): Fragment {
    val pageInfo = items[position]
    val fragment = fragmentFactory.instantiate(classLoader, pageInfo.fragmentClass.name)
    fragment.arguments = Bundle().also { it.putParcelable(PAGE_INFO, pageInfo) }
    return fragment
}

fun getFragmentName(position: Int) = items[position].fragmentClass.simpleName

fun removeFragment(position: Int) {
    items.removeAt(position)
    notifyItemRemoved(position)
    notifyItemRangeChanged(position, items.size)
    notifyDataSetChanged()
}

删除片段代码:
      if ((view_pager.adapter as TipsAdapter).getFragmentName(index + 1).equals(
            TripPreFragment::class.simpleName) &&
            viewModel.shouldRemoveBulkApply()) {
            (view_pager.adapter as TipsAdapter).removeFragment(index + 1)
            view_pager.setCurrentItem(index + 1, true)
        } else {
            view_pager.setCurrentItem(index + 1, true)
        }

我有两个片段,mainfragment和otherfragment。我正在在每5个位置后添加otherfragment,它不在arraylist中,那么如果它不在列表中,如何删除它? 我正在使用viewpager2。 - Bhavin Patel
2个回答

56
最后,这个方法对我有效。当我们调用notifyDataSetChanged()时,安卓系统会调用适配器中的方法getItemId()来检查该项是否已被更新。它返回代码源中的位置。这意味着在列表0..i..n中,如果你移除了i,它将变成0...i...n-1i不会改变,适配器中的数据也不会更新。请注意保留HTML标签。
    /**
 * Default implementation works for collections that don't add, move, remove items.
 * <p>
 * TODO(b/122670460): add lint rule
 * When overriding, also override {@link #containsItem(long)}.
 * <p>
 * If the item is not a part of the collection, return {@link RecyclerView#NO_ID}.
 *
 * @param position Adapter position
 * @return stable item id {@link RecyclerView.Adapter#hasStableIds()}
 */
@Override
public long getItemId(int position) {
    return position;
}

您需要做的是重新编写这个方法和containsItem(long)方法,

对于我的情况,我使用每个片段的哈希码:

class TipsAdapter(
     private val items: MutableList<TripPreferencesOptimizerPage>,
     context: FragmentActivity
    ) : FragmentStateAdapter(context) {

private val fragmentFactory = context.supportFragmentManager.fragmentFactory
private val classLoader = context.classLoader
private val pageIds= items.map { it.hashCode().toLong() }

override fun getItemCount(): Int = items.size

override fun createFragment(position: Int): Fragment {
    val pageInfo = items[position]
    val fragment = fragmentFactory.instantiate(classLoader, pageInfo.fragmentClass.name)
    fragment.arguments = Bundle().also { it.putParcelable(PAGE_INFO, pageInfo) }
    return fragment
}

fun getFragmentName(position: Int) = items[position].fragmentClass.simpleName

fun removeFragment(position: Int) {
    items.removeAt(position)
    notifyItemRangeChanged(position, items.size)
    notifyDataSetChanged()
}

override fun getItemId(position: Int): Long {
    return items[position].hashCode().toLong() // make sure notifyDataSetChanged() works
}

override fun containsItem(itemId: Long): Boolean {
    return pageIds.contains(itemId)
}
}

4
@Xianwei 这是API完全不同的部分,不幸的是与此无关。 - NoHarmDan
2
每次更新数字时,您还需要重新初始化 pageIds = items.map { it.hashCode().toLong() } - Mihae Kheel
谢谢您提供的解决方案。我已经尝试过了,发现调用notifyDataSetChanged实际上是不必要的,甚至会产生一个丑陋的副作用,即当删除最后一页时,视图翻页器会跳转到第一页。在大多数情况下,您希望看到前一页。此外,正如@MihaeKheel所评论的那样,在removeFragment()方法中更新pageId映射是必要的,以保持页面ID和项目同步。 - user3386180
适配器构造函数中的“items”是什么?它是分页片段的本地缓存吗? - Dibzmania
1
对我来说,它可以在没有 notifyItemRangeChangednotifyDataSetChanged 的情况下工作;只需添加 notifyItemRemoved - Zain
显示剩余5条评论

0

最简单的解决方案如下...

items.removeAt(position)
notifyDataSetChanged()

然后从您的活动或片段中调用此函数

view_pager.setCurrentItem(index - 1, true)

如果您正在查看删除片段,那么此操作将删除该片段并像在recyclerview中删除项目一样进行动画处理。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接