【问题标题】:How to make a RecyclerView adapter for a data model with nested lists如何为具有嵌套列表的数据模型制作 RecyclerView 适配器
【发布时间】:2016-11-09 20:57:42
【问题描述】:

给定一个具有对象列表的数据模型,这些对象具有自己的列表作为属性:

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

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

如何根据这些数据创建RecyclerView.Adapter

【问题讨论】:

    标签: android android-recyclerview listobject


    【解决方案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——将展平位置映射到组/子位置,甚至是组/子模型项本身。

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

    总而言之:您的数据是二维的。您设备上的列表是一维的。想想你的数据在设备上应该是什么样子,然后编写一个适配器来实现这一点。

    【讨论】:

    • List 有 List,必须使用 RecyclerView 将 xml 添加到 rander
    • 我真的很喜欢您的回答,但在实际实施时遇到了问题。您能否提供一些示例代码的链接?
    • 虽然建议的解决方案适用于简单的情况,但是在实现 getItemViewType() 和为头子布局选择不同的视图时引入了太多的复杂性。似乎最好的解决方案是使用 ExpandableListview 处理 2D 列表。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-11
    • 1970-01-01
    • 2017-03-27
    • 2019-05-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多