在 RecyclerView.ViewHolder 中添加片段
Add fragment in RecyclerView.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();
}
}
这段代码的问题是所有的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();
}
}
现在每个ViewHolder都正确添加了fragment,并且有了自己的fragment。但是,当我添加 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.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)
我的猜测是 id 在某些时候发生冲突,或者视图由于 ViewHolder 模式而被破坏。所以我的问题是。
1) 有什么解决方法吗?
2)有没有比添加片段更好的做法。我添加片段的原因是 ViewHolder 的子项的逻辑都可以位于单个片段中。当然,我可以将片段的两个视图都放入 ViewHolder xml。并且只是 setVisible() 取决于条件。但这只会让我的 ViewHolder 包含太多逻辑。
以防有人对我为什么需要片段感到困惑。这就是我想要实现的目标。
The image
简短回答:您不应该在 recyclerView 中使用片段,这不是它们的目的。
长答案:here
onBindViewHolder:
yourFragment fragment = new yourFragment();
try {
viewHolder.Fragment(fragment);
}catch (Exception e){
Toast.makeText(context, "BindViewHolder"+e.getMessage(), Toast.LENGTH_SHORT).show();
}
ViewHolder:
class ViewHolder extends RecyclerView.ViewHolder {
TextView name;
FrameLayout container;
private ViewHolder(@NonNull View itemView) {
super(itemView);
container = itemView.findViewById(R.id.fragmentContainer);
}
private void Fragment(final Fragment fragment) {
FragmentTransaction transaction = ((AppCompatActivity) context).getSupportFragmentManager()
.beginTransaction();
try {
transaction.add(R.id.fragmentContainer, fragment)
.commit();
} catch (Exception e) {
Toast.makeText(context, "ViewHolder " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
你应该知道recyclerview创建了你的holder并为他画了一个视图,所以你需要在你的适配器的onViewAttachedToWindow
方法中附加一个片段。在您的 "attaching fragment" 方法中,您应该检查片段管理器是否已经包含这些片段以防止创建多个实例。
适配器:
override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
if(holder is FragmentsHolder){
attachFragmentToContainer(holder.flContainer)
}
super.onViewAttachedToWindow(holder)
}
方法实现:
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()
}
}
这对大量用户进行了测试 - 没有崩溃,性能良好。
我遇到了同样的问题并通过在我的 onBindViewHolder 回调中使用 addOnChildAttachStateChangeListener
RecyclerView 回调解决了它:
listView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
@Override
public void onChildViewAttachedToWindow(@NotNull View view) {
//Create your fragment container here using the view param and add your fragment to the container
}
@Override
public void onChildViewDetachedFromWindow(@NotNull View view) {
//Destroy the fragment container here
}
});
我有一个 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();
}
}
这段代码的问题是所有的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();
}
}
现在每个ViewHolder都正确添加了fragment,并且有了自己的fragment。但是,当我添加 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.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)
我的猜测是 id 在某些时候发生冲突,或者视图由于 ViewHolder 模式而被破坏。所以我的问题是。
1) 有什么解决方法吗?
2)有没有比添加片段更好的做法。我添加片段的原因是 ViewHolder 的子项的逻辑都可以位于单个片段中。当然,我可以将片段的两个视图都放入 ViewHolder xml。并且只是 setVisible() 取决于条件。但这只会让我的 ViewHolder 包含太多逻辑。
以防有人对我为什么需要片段感到困惑。这就是我想要实现的目标。 The image
简短回答:您不应该在 recyclerView 中使用片段,这不是它们的目的。
长答案:here
onBindViewHolder:
yourFragment fragment = new yourFragment();
try {
viewHolder.Fragment(fragment);
}catch (Exception e){
Toast.makeText(context, "BindViewHolder"+e.getMessage(), Toast.LENGTH_SHORT).show();
}
ViewHolder:
class ViewHolder extends RecyclerView.ViewHolder {
TextView name;
FrameLayout container;
private ViewHolder(@NonNull View itemView) {
super(itemView);
container = itemView.findViewById(R.id.fragmentContainer);
}
private void Fragment(final Fragment fragment) {
FragmentTransaction transaction = ((AppCompatActivity) context).getSupportFragmentManager()
.beginTransaction();
try {
transaction.add(R.id.fragmentContainer, fragment)
.commit();
} catch (Exception e) {
Toast.makeText(context, "ViewHolder " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
你应该知道recyclerview创建了你的holder并为他画了一个视图,所以你需要在你的适配器的onViewAttachedToWindow
方法中附加一个片段。在您的 "attaching fragment" 方法中,您应该检查片段管理器是否已经包含这些片段以防止创建多个实例。
适配器:
override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
if(holder is FragmentsHolder){
attachFragmentToContainer(holder.flContainer)
}
super.onViewAttachedToWindow(holder)
}
方法实现:
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()
}
}
这对大量用户进行了测试 - 没有崩溃,性能良好。
我遇到了同样的问题并通过在我的 onBindViewHolder 回调中使用 addOnChildAttachStateChangeListener
RecyclerView 回调解决了它:
listView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
@Override
public void onChildViewAttachedToWindow(@NotNull View view) {
//Create your fragment container here using the view param and add your fragment to the container
}
@Override
public void onChildViewDetachedFromWindow(@NotNull View view) {
//Destroy the fragment container here
}
});