当前位置: 首页 > 知识库问答 >
问题:

展开/折叠嵌套的RecyclerView

江温书
2023-03-14

我有一个带有多个视图保持器的RecyclerView适配器。每个ViewHolder都有一个标题TextView和一个嵌套的RecyclerView,工作正常。但我想实现一个扩展/折叠函数,这样嵌套的RecyclerView就可以隐藏,直到单击标题为止。我使用此方法RecyclerView展开/折叠项目。它可以工作,但当我单击标题以展开嵌套的RecyleView时,recyclerview不会填充任何数据。明确地说,它检索数据,但不可见。你知道为什么会这样吗?

这是我的onBindViewMethod:

public class EligibilityAdapter extends RecyclerView.Adapter<EligibilityAdapter.ViewHolder> {

private Context mContext;
private List<EligibilityDetails> mEligsList;
private List<Items> mItemslist;
private LayoutInflater inflater;
private int mExpandedPosition = -1;

public EligibilityAdapter(Context context, List<EligibilityDetails> eligsList) {
    mContext = context;
    mEligsList = eligsList;
    inflater = LayoutInflater.from(context);
}

@Override
public int getItemViewType(int position) {
    switch (position) {
        case 0:
            return R.layout.rv_eligs_item_domestic;
        case 1:
            return R.layout.rv_eligs_item_overseas;
        default:
            return R.layout.rv_eligs_item_military;
    }
}

@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
    inflater = LayoutInflater.from(viewGroup.getContext());
    View view = inflater.inflate(i, viewGroup, false);
    ViewHolder holder = null;
    switch (i) {
        case R.layout.rv_eligs_item_domestic:
            holder = new DomesticViewHolder(view);
            break;
        case R.layout.rv_eligs_item_overseas:
            holder = new OverseasViewHolder(view);
            break;
        case R.layout.rv_eligs_item_military:
            holder = new MilitaryViewHolder(view);
            break;
    }
    return holder;
}

@Override
public int getItemCount() {
    return mEligsList.size();
}

public abstract class ViewHolder extends RecyclerView.ViewHolder {
    RecyclerView itemsRv;
    TextView mHeader;
    ItemsAdapter adapter;

    public ViewHolder(View itemView) {
        super(itemView);
        mHeader = (TextView) itemView.findViewById(R.id.header_tv);
        itemsRv = itemView.findViewById(R.id.recyclerViewItems);
    }
    public void setData(List<Items> list) {
        adapter.updateList(list);
    }
    abstract void bind(EligibilityDetails item);
}

public class DomesticViewHolder extends ViewHolder {

    TextView mHeader;
    RecyclerView itemsRv;
    ItemsAdapter adapter;

    public DomesticViewHolder(View itemView) {
        super(itemView);
        mHeader = (TextView) itemView.findViewById(R.id.header_tv);
        itemsRv = itemView.findViewById(R.id.recyclerViewItems);
    }
    public void setData(List<Items> list) {
        adapter.updateList(list);
    }
    @Override
    void bind(EligibilityDetails eligibilityDetails) {
        mHeader.setText(eligibilityDetails.getRequirementHeader());
        mItemslist = eligibilityDetails.getItemsList();
        ItemsAdapter itemsAdapter = new ItemsAdapter(mContext, mItemslist);
        itemsRv.setHasFixedSize(true);
        itemsRv.setLayoutManager(new CustomLinearLayoutManager(mContext));
        itemsRv.setAdapter(itemsAdapter);
        itemsRv.setNestedScrollingEnabled(false);
    }
}

public class OverseasViewHolder extends ViewHolder {

    TextView mHeader;
    RecyclerView itemsRv;
    ItemsAdapter adapter;

    public OverseasViewHolder(View itemView) {
        super(itemView);
        mHeader = (TextView) itemView.findViewById(R.id.header_tv);
        itemsRv = itemView.findViewById(R.id.recyclerViewItems);
    }
    public void setData(List<Items> list) {
        adapter.updateList(list);
    }

    @Override
    void bind(EligibilityDetails eligibilityDetails) {
        mHeader.setText(eligibilityDetails.getRequirementHeader());
        mItemslist = eligibilityDetails.getItemsList();
        ItemsAdapter itemsAdapter = new ItemsAdapter(mContext, mItemslist);
        itemsRv.setHasFixedSize(true);
        itemsRv.setLayoutManager(new CustomLinearLayoutManager(mContext));
        itemsRv.setAdapter(itemsAdapter);
        itemsRv.setNestedScrollingEnabled(false);
    }
}

public class MilitaryViewHolder extends ViewHolder {

    TextView mHeader;
    RecyclerView itemsRv;
    ItemsAdapter adapter;

    public MilitaryViewHolder(View itemView) {
        super(itemView);
        mHeader = (TextView) itemView.findViewById(R.id.header_tv);
        itemsRv = itemView.findViewById(R.id.recyclerViewItems);
    }
    public void setData(List<Items> list) {
        adapter.updateList(list);
    }

    @Override
    void bind(EligibilityDetails eligibilityDetails) {
        mHeader.setText(eligibilityDetails.getRequirementHeader());
        mItemslist = eligibilityDetails.getItemsList();
        final ItemsAdapter itemsAdapter = new ItemsAdapter(mContext, mItemslist);
        itemsRv.setHasFixedSize(true);
        itemsRv.setLayoutManager(new CustomLinearLayoutManager(mContext));
        itemsRv.setAdapter(itemsAdapter);
        itemsRv.setNestedScrollingEnabled(false);
    }
}

@Override
public void onBindViewHolder(@NonNull final EligibilityAdapter.ViewHolder viewHolder, int i) {
    viewHolder.bind(mEligsList.get(i));

    final boolean isExpanded = i == mExpandedPosition;
    viewHolder.itemsRv.setVisibility(isExpanded?View.VISIBLE:View.GONE);
    viewHolder.itemView.setActivated(isExpanded);
    viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mExpandedPosition = isExpanded ? -1:viewHolder.getAdapterPosition();
            ItemsAdapter itemsAdapter = new ItemsAdapter(mContext, mItemslist);
            viewHolder.itemsRv.setAdapter(itemsAdapter);
            //TransitionManager.beginDelayedTransition(recyclerView);
            notifyDataSetChanged();
        }
    });
}

其中itemsRv是嵌套的RecycleView。我尝试过将此逻辑移动到各个视图所有者,并将回收器视图逻辑移动到这里,就像在onClick方法中设置适配器一样。每次它都是空白的。

提前感谢。

共有1个答案

万俟飞语
2023-03-14

您可以创建一个多视图类型适配器,为您的标题创建一个视图类型,为您的子项创建一个视图类型,而不是为每个标题创建一个新的子< code > recycle view 。

不要只对数据列表使用标头数据项,而应使用允许将每种数据类型转换为其自己的视图类型的泛型类型。

为此,我们需要创建一个空接口,我们所有的数据类型都将以这种方式实现,它们都是泛型的。

public interface GenericDataType {}

因此,您的数据类型将如下所示

class HeaderItem implements GenericDataType {
    //All of your pojo data
    List<ChildrenItem> childrens; //ChildrenItem will also implement the GenericDataType that way both of the items are acceptable
}

所以我们可以替换当前的项目

private List<EligibilityDetails> mEligsList;
private List<Items> mItemslist;

private List<GenericDataType> adapterItems;

现在,我们需要确保每当我们拥有某个< code > viewmoder 时,该位置的项目都是正确的类型。为此,我们需要更改我们的< code>getItemViewType

@Override
public int getItemViewType(int position) {
    GenericItem currentItem = adapterItems.get(position);

    if (currentItem instanceOf HeaderItem) { //We have to use if else becasue java's switch does not supprt checking instancesOf
        return R.layout.your_header_item_layout_id;

    } else if(currentItem instanceOf ChildrenItem) {
        return R.layout.your_children_item_layout_id;

    } else if(repeat for any other types you have) {
        return R.layout.your_other_item_layout_id;

    } else {
        throw new Throwable("Unsupported type"); //This should never happen but we add it to make the compiler compile
    }
}

现在,我们终于可以将onBind方法更改为支持这两种类型

@Override
public void onBindViewHolder(@NonNull final  EligibilityAdapter.ViewHolder viewHolder, int i) {

    if (viewHolder instanceOf HeaderViewHolder) {
        HeaderViewHolder holder = (HeaderViewHolder) viewHolder;
        headerItem = (HeaderItem) items.get(i);
        //Do rest of binding here

        holder.viewToAddMoreItems.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!headerItem.isEpanded()) { //Add to your header type a Boolean to check if it is expanded or not 
                    adapterItems.addAll(headerItem.getChildrens()); //They are the same generic type but the getItemViewType will handle it for us
                    notifyItemRangeInserted(); //Provied item start index and size of the list
                } else {
                    adapterItems.removeAll(headerItem.getChildrens());
                    notifyItemRangeRemoved(); I don't remember what it require but you'll figure that out
                }
                headerItem.setExpanded(!headerItem.isExpanded()); //Flipping the value 
            }
        });

    } else if (viewHolder instanceOf ChildrenViewHolder) {
            ChildrenViewHolder holder = (ChildrenViewHolder) viewHolder;
            childrenItem = (ChildrenItem) items.get(i);
            //Do your binding here

    } else if(repeate for other view-types) {}
}
 类似资料:
  • 展开或折叠代码 操作步骤: 菜单栏:Code —> Folding —> Expand 快捷键: Mac: command + “+” Windows\/Linux: Ctrl + "+" 展开或折叠代码 操作步骤: 菜单栏:Code —> Folding —> Collapse 快捷键: Mac: command + “-” Windows\/Linux: Ctrl + "-" 展开或折叠当前代

  • 问题内容: 我能够展开和折叠单元格,但我想在UITableViewCell内调用函数(展开和折叠)以更改按钮标题。 问题答案: 如果你想在细胞获得更大的身体,那么,你有你的店,在使用: 然后,当您想在didSelectRow中展开一个时: 编辑 这将使单元动画自己变大,您不需要单元中额外的动画块。 编辑2

  • 我想展开/折叠我的recyclerView项目,以显示更多信息。我想实现与SlideExpandableListView相同的效果。 基本上,在我的viewHolder中,我有一个不可见的视图,我想做一个平滑的展开/折叠动画,而不是将可见性设置为仅可见/消失。我一次只需要扩展一个项目,如果有一些提升来显示该项目已被选中,那就太酷了。 这与新的Android最近通话历史记录列表的效果相同。“回调”和

  • I',试图构建一个扩展/折叠菜单。 我有一个主导航栏,里面有3个子菜单。默认情况下,子菜单的高度为50px,但一旦点击,这个高度就会变为200px。再点击一下,让它塌陷回原来的50px。 让我烦恼的是,当我展开subMenu1,然后展开Submenu2-Submenu1保持展开,并且我希望它在第二个子菜单被选中时折叠。 这是我的代码; 和jQuery: 我想知道什么功能或什么使用来确保一旦任何子菜

  • 问题 你想将一个多层嵌套的序列展开成一个单层列表 解决方案 可以写一个包含 yield from 语句的递归生成器来轻松解决这个问题。比如: from collections import Iterable def flatten(items, ignore_types=(str, bytes)): for x in items: if isinstance(x, Ite

  • 我设法做了我的卡视图适配器,但我阻止放大我的卡。我恢复了这个响应的代码(这里类的名称是:)来做动画,但它是叠加的。 我解决了上面的问题,但是如果在我的cardView上,我同时显示10个元素,一个50个元素的列表。如果我展开第一个,数字11,21,31,41也会展开。你有办法让这种情况不发生吗? 我已经反思了,这对我来说毫无意义。在我的 OnClick 方法之前,我显示一个文本视图,其中文本是位置