[英]How to make single selection work in a nested RecyclerView
For our application I had to implement a nested RecyclerView.对于我们的应用程序,我必须实现一个嵌套的 RecyclerView。 I'm getting a list of Tables from JSON and every Table has another list with groups from each table.
我从 JSON 获得了一个表列表,每个表都有另一个列表,其中包含每个表中的组。 I can get everything on the screen as requested, the problem is the selection.
我可以按要求在屏幕上显示所有内容,问题在于选择。
I have 2 different RecyclerViews on the screen and I can not seem to get a single selection working in this environment, especially after scrolling.我在屏幕上有 2 个不同的 RecyclerViews,我似乎无法在这种环境中获得单个选择,尤其是在滚动之后。 Every group and every table has a Toggle Button, and only one can be active at a time.
每个组和每个表都有一个切换按钮,一次只能激活一个。
This is how the main screen looks like这是主屏幕的样子
So far I've tried putting a boolean isSelected on the Model but that didn't work out at all.到目前为止,我已经尝试将 boolean isSelected 放在 Model 上,但这根本没有成功。 The closest solution I came up with was a helper class that searches every CompoundButton on-screen and deselects them all when one is selected.
我想出的最接近的解决方案是一个助手 class 搜索屏幕上的每个 CompoundButton 并在选择一个时取消选择它们。 The problem is this helper class cant get the Buttons which are off-screen.
问题是这个助手 class 无法获取屏幕外的按钮。
How I populate ParentAdapter (in MainActivity):我如何填充 ParentAdapter(在 MainActivity 中):
public void setAdapter(List<Table> tableList)
{
RecyclerView recycler_view_parent = findViewById(R.id.recyclerparent);
LinearLayoutManager manager=new LinearLayoutManager(MainActivity.this);
manager.setOrientation(LinearLayoutManager.HORIZONTAL);
recycler_view_parent.setLayoutManager(manager);
recycler_view_parent.setHasFixedSize(true);
recycler_view_parent.setItemViewCacheSize(tableList.size());
ParentAdapter parentAdapter=new ParentAdapter(tableList,MainActivity.this);
recycler_view_parent.setAdapter(parentAdapter);
}
How i populate ChildAdapter (in onBindViewHolder of ParentAdapter):我如何填充 ChildAdapter(在 ParentAdapter 的 onBindViewHolder 中):
FlexboxLayoutManager manager = new FlexboxLayoutManager(context);
manager.setFlexDirection(FlexDirection.COLUMN);
manager.setJustifyContent(JustifyContent.FLEX_START);
manager.setFlexWrap(FlexWrap.WRAP);
manager.setAlignItems(AlignItems.BASELINE);
holder.recycler_view_child.setLayoutManager(manager);
holder.recycler_view_child.setHasFixedSize(true);
adapter = new ChildAdapter(tableList, tableList.get(position).getGroups(), context);
holder.recycler_view_child.setAdapter(adapter);
The desired output should be only 1 Table OR Group at a time can be toggled (in total, not one from every RecyclerView) and the state should be the same after scrolling/device rotation).所需的 output 一次只能切换 1 个表或组(总共,不是每个 RecyclerView 中的一个),并且 state 在滚动/设备旋转后应该相同)。
I did a lot of research over the last days on this subject and I can not seem to find a working example of nested RecyclerView with single selection over both RVs.在过去的几天里,我对这个主题进行了很多研究,但我似乎找不到嵌套 RecyclerView 的工作示例,其中单选两个 RV。
So does anyone have an idea on how to solve this?那么有人知道如何解决这个问题吗? I think the biggest issue is telling the Parent that a Button in Child was toggled and vice-versa.
我认为最大的问题是告诉家长孩子中的按钮被切换,反之亦然。
I think for the ParentAdapter it should look something like this:我认为对于 ParentAdapter 它应该是这样的:
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
final Table table = tablelist.get(position);
ViewHolder viewHolder = (ViewHolder) holder;
if (table.isTableSelected()) {
viewHolder.toggletable.setChecked(true);
lastToggled = position;
} else {
viewHolder.toggletable.setChecked(false);
}
viewHolder.toggletable.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if (b) {
table.setTableSelected(true);
// notify ChildAdapter and group.setGroupSelected(false)
if (lastToggled >= 0) {
tablelist.get(lastToggled).setTableSelected(false);
// notify ChildAdapter and group.setGroupSelected(false)
notifyItemChanged(lastToggled);
}
lastToggled = position;
} else {
table.setTableSelected(false);
}
}
});
}
Thanks in advance.提前致谢。
UPDATE: Managed to come up with a solution myself, although 100% sure, not the best approach.更新:自己设法想出了一个解决方案,虽然 100% 肯定,但不是最好的方法。
First of all, implement Greenrobots EventBus:首先,实现 Greenrobots EventBus:
implementation 'org.greenrobot:eventbus:3.1.1'
Now in the Activity where you hold both RecyclerViews register the Event listener:现在在您持有两个 RecyclerViews 的 Activity 中注册事件侦听器:
@Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
and subscribe 2 methods.并订阅 2 种方法。 One for Parent Events and one for Children Events.
一种用于家长活动,一种用于儿童活动。 This methods will trigger every time an item is selected!
每次选择项目时都会触发此方法!
@Subscribe(threadMode = ThreadMode.MAIN)
public void onParentEventClicked(ParentAdapter.ParentEvent event) {
// to access the inner adapter here you must set it to public in the ParentAdapter(public ChildAdapter adapter;)
adapter.adapter.deSelectChild();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onChildEventClicked(ChildAdapter.ChildEvent event) {
// normal ParentAdapter reference(ParentAdapter adapter;)
adapter.deSelectParent();
}
Inside your ParentAdapter create a method to deselect all parent items and a static class to fire the event:在 ParentAdapter 中创建一个取消选择所有父项的方法和一个 static class 来触发事件:
public void deSelectParent()
{
for (int i=0;i<data.size();i++)
{
data.get(i).setSelected(false);
}
notifyDataSetChanged();
}
public static class ParentEvent {
View view;
int position;
}
Inside your ChildAdapter create a method to deselect all child items and a static class to fire the event:在您的 ChildAdapter 中创建一个取消选择所有子项的方法和一个 static class 来触发事件:
public void deSelectChild()
{
for (int i=0;i<data.size();i++)
{
datachild.get(i).setSelected(false);
}
notifyDataSetChanged();
}
public static class ChildEvent {
View view;
int position;
}
now in both Parent and Child onBindViewHolders, you need similar logic for your models:现在在 Parent 和 Child onBindViewHolders 中,您的模型需要类似的逻辑:
if (item.isSelected()) {
holder.yourbutton.setChecked(true);
} else {
holder.yourbutton.setChecked(false);
}
holder.yourbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ParentEvent event = new ParentEvent();
event.view = holder.yourbutton;
event.position = position;
EventBus.getDefault().post(event);
if (holder.yourbutton.isChecked()) {
for (int i = 0; i < data.size(); i++) {
data.get(i).setSelected(false);
}
data.get(position).setSelected(true);
} else {
data.get(position).setSelected(false);
}
notifyDataSetChanged();
}
});
And thats pretty much it, every click on a ParentItem will trigger the deselect method for ChildAdapter and vice-versa.差不多就是这样,每次单击 ParentItem 都会触发 ChildAdapter 的取消选择方法,反之亦然。 Due to the high usage of notifyDataSetChanged() I recommend using this line to get rid of the blinking:
由于 notifyDataSetChanged() 的使用率很高,我建议使用这一行来摆脱闪烁:
recycler_view_parent.setItemAnimator(null);
Any problems let me know!有什么问题告诉我!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.