简体   繁体   English

如何在嵌套的 RecyclerView 中进行单选工作

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM