在RecyclerView.ViewHolder中添加片段

Gin*_*san 10 android android-fragments android-viewholder

我有一个RecyclerView.ViewHolder,它将根据传递的对象的实例将不同的片段添加到其FrameLayout中。问题来了,几乎不可能在ViewHolder中添加片段。请注意,我已经从父级传递了FragmentManager。最初我尝试使用此代码

public void setSomething(boolean A) {
    if (A) {
         mFragmentManager.beginTransaction()
            .replace(mBinding.typeContainerLayout.getId(), new FragmentA())
            .commit();
    } else {
        mFragmentManager.beginTransaction()
            .replace(mBinding.typeContainerLayout.getId(), new FragmentB())
            .commit();
    }
}
Run Code Online (Sandbox Code Playgroud)

这段代码的问题是所有ViewHolder共享相同的ID,因此只有一个ViewHolder可以添加片段。在我的RecyclerView中,只有第一个单元添加了片段。为了解决这个问题,我创建了另一个FrameLayout并将其添加到中typeContainerLayout。现在我的代码变成这样。

public void setSomething(boolean A) {
    FrameLayout frameLayout = new FrameLayout(mContext);
    frameLayout.setId(View.generateViewId());
    mBinding.typeContainerLayout.removeAllViews();
    mBinding.typeContainerLayout.addView(frameLayout)

    if (A) {
         mFragmentManager.beginTransaction()
            .replace(frameLayout.getId(), new FragmentA())
            .commit();
    } else {
        mFragmentManager.beginTransaction()
            .replace(frameLayout.getId(), new FragmentB())
            .commit();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,每个ViewHolder都正确添加了片段,并拥有自己的片段。但是,当我添加类似5的ViewHolder并尝试向下滚动RecyclerView时,就会出现问题,出现运行时错误

java.lang.IllegalArgumentException: No view found for id 0x4 (unknown) for fragment FragmentA{7c55a69 #0 id=0x4 FragmentA}
                      at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1292)
                      at android.support.v4.app.FragmentManagerImpl.moveFragmentsToInvisible(FragmentManager.java:2323)
                      at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2136)
                      at android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.java:2092)
                      at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1998)
                      at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:709)
                      at android.os.Handler.handleCallback(Handler.java:739)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:148)
                      at android.app.ActivityThread.main(ActivityThread.java:5417)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Run Code Online (Sandbox Code Playgroud)

我的猜测是id有时冲突,或者由于ViewHolder模式导致视图被破坏。所以我的问题是。

1)有什么解决方法吗?

2)有没有比添加片段更好的做法。我添加片段的原因是为了使ViewHolder子项的逻辑都可以位于一个片段中。当然,我可以将片段的两个视图都放入ViewHolder xml中。并根据情况设置setVisible()。但这只会使我的ViewHolder包含太多逻辑。

万一有人困惑我为什么需要片段。这就是我要实现的目标。 图片

Art*_*yan 8

您应该确切地知道 recyclerview 创建了您的持有人并为他绘制了一个视图,因此您需要在onViewAttachedToWindow适配器的方法中附加一个片段。在您的“附加片段”方法中,您应该检查片段管理器是否已经包含这些片段以防止创建多个实例。

适配器:

 override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {    
    if(holder is FragmentsHolder){
        attachFragmentToContainer(holder.flContainer)            
    }
    super.onViewAttachedToWindow(holder)
}
Run Code Online (Sandbox Code Playgroud)

方法实现:

 fun attachFragmentToContainer(containerId: Int) {
    val fragment = if (fragmentManager?.fragments?.firstOrNull { it is YourFragment } == null)
        YourFragment.instance()
    else
        null

    if (fragment != null) {
        fragmentManager?.beginTransaction()
            ?.add(containerId, fragment)
            ?.commitNowAllowingStateLoss()
    }
}
Run Code Online (Sandbox Code Playgroud)

这对大量用户进行了测试 - 没有崩溃,性能良好。


Han*_*aim 5

简短的答案:您不应该在recyclerView中使用片段,这不是它们的目的。

长答案:这里

  • 我不认为这是一个正确的答案,当然我们可以在 recyclerView 中使用片段。如果您的应用程序中有一个复杂的 UI,有时需要使用某种 hack。请在下面查看我的答案:/sf/answers/3942691791/ (6认同)
  • 这个答案不正确。`androidx` `ViewPager2` 在 RecyclerView 中使用 `Fragment`。请参阅适配器的`placeFragmentInViewHolder`方法:https://github.com/androidx/androidx/blob/androidx-master-dev/viewpager2/viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentStateAdapter.java (3认同)