You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

父子项均含多字段时,如何用JSON数据填充ExpandableListView?

嘿,这个需求其实挺常见的,完全可以实现!我来一步步给你讲清楚怎么做:

1. 先定义数据模型类

咱们先把父项和子项的数据结构定下来,因为两者都有nome和comentario字段,父项还多了一个子项列表resp。分开定义两个模型类会更清晰,避免混淆:

// 父项数据模型
public class ParentComment {
    private String nome;
    private String comentario;
    private List<ChildComment> resp;

    // 构造方法、getter和setter必须齐全
    public ParentComment(String nome, String comentario, List<ChildComment> resp) {
        this.nome = nome;
        this.comentario = comentario;
        this.resp = resp;
    }

    public String getNome() { return nome; }
    public void setNome(String nome) { this.nome = nome; }
    public String getComentario() { return comentario; }
    public void setComentario(String comentario) { this.comentario = comentario; }
    public List<ChildComment> getResp() { return resp; }
    public void setResp(List<ChildComment> resp) { this.resp = resp; }
}

// 子项数据模型
public class ChildComment {
    private String nome;
    private String comentario;

    public ChildComment(String nome, String comentario) {
        this.nome = nome;
        this.comentario = comentario;
    }

    public String getNome() { return nome; }
    public void setNome(String nome) { this.nome = nome; }
    public String getComentario() { return comentario; }
    public void setComentario(String comentario) { this.comentario = comentario; }
}

2. 解析你的JSON数据

接下来把你提供的JSON字符串转换成上面定义的模型列表。推荐用Gson库来解析,方便又省心。如果还没加依赖,先在build.gradle里添加:

dependencies {
    implementation 'com.google.code.gson:gson:2.10.1'
}

然后解析代码如下:

// 把你的JSON字符串替换成实际的数据源
String jsonString = "[ { \"nome\": \"Carlos\", \"comentario\": \"Esse dia foi show\", \"resp\": [ ] }, { \"nome\": \"Andre\", \"comentario\": \"Acho que não precisava disso\", \"resp\": [ { \"nome\": \"inutil\", \"comentario\": \"Sempre assim\" }, { \"nome\": \"Roberto\", \"comentario\": \"Se não estivessem fazendo nada errado,...\" } ] } ]";

Gson gson = new Gson();
Type listType = new TypeToken<List<ParentComment>>(){}.getType();
List<ParentComment> parentCommentList = gson.fromJson(jsonString, listType);

3. 自定义ExpandableListAdapter

核心部分来了,咱们要写一个自定义适配器,继承BaseExpandableListAdapter,重写关键方法来加载自定义布局并设置多字段数据:

public class CustomExpandableListAdapter extends BaseExpandableListAdapter {
    private Context mContext;
    private List<ParentComment> mParentList;

    public CustomExpandableListAdapter(Context context, List<ParentComment> parentList) {
        mContext = context;
        mParentList = parentList;
    }

    @Override
    public int getGroupCount() {
        return mParentList.size();
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return mParentList.get(groupPosition).getResp().size();
    }

    @Override
    public Object getGroup(int groupPosition) {
        return mParentList.get(groupPosition);
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return mParentList.get(groupPosition).getResp().get(childPosition);
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    @Override
    public boolean hasStableIds() {
        return false;
    }

    // 渲染父项布局
    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        ParentComment parentComment = (ParentComment) getGroup(groupPosition);
        
        // 复用布局提升性能
        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.group_item, parent, false);
        }

        // 找到布局里的TextView,设置数据
        TextView tvNome = convertView.findViewById(R.id.tv_group_nome);
        TextView tvComentario = convertView.findViewById(R.id.tv_group_comentario);

        tvNome.setText(parentComment.getNome());
        tvComentario.setText(parentComment.getComentario());

        return convertView;
    }

    // 渲染子项布局
    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        ChildComment childComment = (ChildComment) getChild(groupPosition, childPosition);
        
        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.child_item, parent, false);
        }

        TextView tvNome = convertView.findViewById(R.id.tv_child_nome);
        TextView tvComentario = convertView.findViewById(R.id.tv_child_comentario);

        tvNome.setText(childComment.getNome());
        tvComentario.setText(childComment.getComentario());

        return convertView;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true; // 如果需要子项可点击,就返回true
    }
}

4. 编写父项和子项的布局文件

接下来创建两个布局文件,分别对应父项和子项的UI,把nome和comentario显示出来:

父项布局 res/layout/group_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
        android:id="@+id/tv_group_nome"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:textStyle="bold"/>

    <TextView
        android:id="@+id/tv_group_comentario"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="14sp"
        android:layout_marginTop="4dp"/>

</LinearLayout>

子项布局 res/layout/child_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="16dp"
    android:layout_marginLeft="24dp"> <!-- 子项缩进,视觉层级更清晰 -->

    <TextView
        android:id="@+id/tv_child_nome"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:textStyle="italic"/>

    <TextView
        android:id="@+id/tv_child_comentario"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="14sp"
        android:layout_marginTop="4dp"/>

</LinearLayout>

5. 在页面中配置ExpandableListView

最后一步,在你的Activity或Fragment里初始化ExpandableListView,把适配器设置进去:

public class MainActivity extends AppCompatActivity {
    private ExpandableListView mExpandableListView;
    private CustomExpandableListAdapter mAdapter;
    private List<ParentComment> mParentCommentList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mExpandableListView = findViewById(R.id.expandable_list);

        // 这里执行JSON解析,获取mParentCommentList(就是步骤2里的代码)
        String jsonString = "[ { \"nome\": \"Carlos\", \"comentario\": \"Esse dia foi show\", \"resp\": [ ] }, { \"nome\": \"Andre\", \"comentario\": \"Acho que não precisava disso\", \"resp\": [ { \"nome\": \"inutil\", \"comentario\": \"Sempre assim\" }, { \"nome\": \"Roberto\", \"comentario\": \"Se não estivessem fazendo nada errado,...\" } ] } ]";
        Gson gson = new Gson();
        Type listType = new TypeToken<List<ParentComment>>(){}.getType();
        mParentCommentList = gson.fromJson(jsonString, listType);

        // 设置适配器
        mAdapter = new CustomExpandableListAdapter(this, mParentCommentList);
        mExpandableListView.setAdapter(mAdapter);
    }
}

这样就能完美实现你要的效果啦,父项和子项都能显示名称和评论字段~

内容的提问来源于stack exchange,提问作者user2950020

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:57:09