如何为具有嵌套列表的数据模型制作RecyclerView适配器

时间:2016-07-07 13:47:06

标签: android android-recyclerview listobject

给定一个数据模型,其中包含具有自己的列表作为属性的对象列表:

private ObservableArrayList<BasProduct> basProducts = new ObservableArrayList<>();

//the model BasProduct have below attribute
public List<String> newOrderNotes;
public List<BasGoods> basGoodses;

如何制作基于此数据的RecyclerView.Adapter

1 个答案:

答案 0 :(得分:1)

您的RecyclerView列表视图是一维的。您的列表模型是二维的。因此,您需要一个列表适配器,将二维模型展平为一维模型。

所以,假设你有这个模型:

BasProduct[0]
    OrderNote[0]
    OrderNote[1]
    BasGoods[0]
    BasGoods[1]
BasProduct[1]
    OrderNote[0]
    OrderNote[1]
    BasGoods[0]
    BasGoods[1]

即。你有两个产品,每个产品的两个产品都有两个产品。

现在你必须把它变成这个:

[0]    BasProduct[0]
[1]        OrderNote[0]
[2]        OrderNote[1]
[3]        BasGoods[0]
[4]        BasGoods[1]
[5]    BasProduct[1]
[6]        OrderNote[0]
[7]        OrderNote[1]
[8]        BasGoods[0]
[9]        BasGoods[1]

有很多方法可以做到这一点,诀窍是设计一种方法,这样你就不会编写隐藏在其中的大量错误的混淆代码。

我所做的是使用ExpandableListAdapter作为模板并从那里构建。所以我为getGroupCount()getChildCount()编写了实现。然后我使用这些方法实现了getItemCount()

    @Override
    public int getItemCount() {

       int count = 0;
       int groupCount = getGroupCount();
       for (int i = 0; i < groupCount; i++) {
           count++;
           if (mGroupExpanded[i]) {
                count += getChildCount(i);
           }
       }

       return count;
    }

你可以在我的代码中看到我有一个组扩展标志的布尔数组。我让我的RecyclerView具有可扩展组,因此这意味着需要更多代码来跟踪扩展/折叠状态。

遵循相同的模式,我将绑定拆分为onBindGroupViewHolder()onBindChildViewHolder(),然后使用这些方法实现onBindViewHolder()

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        int pos = 0;
        int groupCount = getGroupCount();
        for (int i = 0; i < groupCount; i++) {
            if (pos == position) {
                onBindGroupViewHolder(holder, i);
                return;
            }
            pos++;
            if (mGroupExpanded[i]) {
                int childCount = getChildCount(i);
                for (int j = 0; j < childCount; j++) {
                    if (pos == position) {
                       onBindChildViewHolder(holder, i, j);
                       return;
                    }
                    pos++;
                }
            }
        }

        throw new IllegalStateException("couldn't determine group/child for raw position = " + position);
    }

然后你需要的最后一块是将getAdapterPosition()返回的扁平位置映射回组位置和子位置的方法:

    private int[] getGroupChildPosition(int position) {

        // positions[0] is group position
        // positions[1] is child position, -1 means it's a group
        int[] positions = new int[2];
        int current = 0;
        int groupCount = getGroupCount();
        for (int currentGroup = 0; currentGroup < groupCount; currentGroup++) {
            if (current == position) {
                positions[0] = currentGroup;
                positions[1] = -1;
                return positions;
            }
            current++;
            if (mGroupExpanded[i]) {
                int childCount = getChildCount(i);
                for (int currentChild = 0; currentChild < childCount; currentChild++) {
                    if (current == position) {
                        positions[0] = currentGroup;
                        positions[1] = currentChild;
                        return positions;
                    }
                    current++;
                }
            }
        }

        throw new IllegalStateException("couldn't determine group/child for raw position = " + position);
    }

您可以采用不同的方式。例如,您可以制作Map - 实际上是SparseArray - 将展平的位置映射到组/子位置,甚至是组/子模型项本身。

所有迭代都是很多开销。我只是展示了如何以一种非常易于理解的方式处理列表。

总而言之:您的数据是二维的。您设备上的列表是一维的。考虑一下您的数据在设备上应该是什么样子,并编写一个执行此操作的适配器。