简体   繁体   English

具有任何深度的嵌套项目的 Recyclerview

[英]Recyclerview with nested items of any depth

I need to display a Recyclerview that can have any amount of subheadings.我需要显示一个可以有任意数量的副标题的 Recyclerview。 Sadly I only found solutions that support a depth of one.可悲的是,我只找到了支持深度为 1 的解决方案。 This isn't enough for my case.这对我的情况来说还不够。

I could have something like this:我可以有这样的东西:

Heading 1
  Subheading 1
    Subsubheading 1
      Subsubsubheading 1
  Subheading 2
Heading 2
...

You get the idea.你明白了。 Futhermore, it would also be quite useful if the user can expand these headings and their content like in MS Word.此外,如果用户可以像在 MS Word 中一样扩展这些标题及其内容,这也将非常有用。 How does one achieve this behaviour (if possible without external libraries)?如何实现这种行为(如果可能没有外部库)? Thank your for you support!感谢您的支持!

For this problem one RecyclerView should be completely enough.对于这个问题,一个RecyclerView应该就足够了。 Your Adapter items should have a tree structure containing a node depth and children.您的Adapter项目应该有一个包含节点深度和子节点的树结构。 Then, based on each item's depth padding of its corresponding view could be changed.然后,可以根据每个项目的深度填充其对应的视图进行更改。

Let's consider a simple example - there's a data class called File as below:让我们考虑一个简单的例子 - 有一个名为File的数据 class 如下:

public class File {
    ...
    public final List<File> children = new ArrayList();
    public boolean isExpanded;
    public boolean isFolder;
    // THIS MUST BE NON-NEGATIVE
    public int depth; 
    ...
}

Then RecyclerView.Adapter (initially you should pass it a list of root files):然后RecyclerView.Adapter (最初你应该将根文件列表传递给它):

...
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    File file = files.get(position);

    holder.itemView.setPadding(Math.min(depth, <MAX_PADDING>) * <leftPadding>, 0, <rightPadding>, 0);

    holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (file.isFolder) {
                if (!file.isExpanded) {
                    expand(holder, file);
                } else {
                    // if you wanna collapse the folder then I'll leave it up to you :)
                } 
            }
        }
    });
}

private void expand(ViewHolder holder, File file) {
    file.isExpanded = true;
    int start = holder.getAdapterPosition();
    files.addAll(start + 1, file.children);
    notifyItemRangeInserted(start + 1, file.children.size());
}
...

If you wanna implement collapse then it's a bit trickier (you'll have to calculate the correct number of items that should be removed from the list) but I'll leave it up to you.如果你想实现collapse ,那么它有点棘手(你必须计算应该从列表中删除的正确项目数),但我会留给你。

I ended up using a combination of the approach from user3170251 and my own.我最终使用了 user3170251 和我自己的方法的组合。 Because my headers are from different models I used an interface and all models implement that interface.因为我的标头来自不同的模型,所以我使用了一个接口,所有模型都实现了该接口。

The recyclerview only gets a list of objects that implement the interface. recyclerview 只获取实现该接口的对象列表。 By checking the type of the current element it knows whether it is a read-only header or a normal element with special on-click functions.通过检查当前元素的类型,它知道它是只读的 header 还是具有特殊点击功能的普通元素。 Now, to have some sort of hierarchy you need to store the depth in the model itself.现在,要拥有某种层次结构,您需要将深度存储在 model 本身中。 So the data hierarchy that the recyclerview sees is still a flat list, but by saving the depth in the model itself I can give headers with a deeper depth a smaller font size.因此,recyclerview 看到的数据层次结构仍然是一个平面列表,但是通过将深度保存在 model 本身中,我可以为深度更深的标题提供更小的字体大小。

The answer from Anshul Aggarwal on Is there an addHeaderView equivalent for RecyclerView? Anshul Aggarwal 关于RecyclerView 是否有一个 addHeaderView 等价物的答案? really helped me out.真的帮了我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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