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

Flutter ListView.builder返回List<ListTile>非Widget类型报错排查

问题结论

ListView.builder与map方法完全可以共同使用,你遇到的报错和二者兼容性无关,核心是回调返回值类型不符合组件的接口要求。另外你贴出的nameAndRollNo数组定义缺少结尾的];,也会触发语法错误。

报错根因

ListView.builder的itemBuilder回调强约束:每次调用必须返回单个Widget实例,对应当前index位置的单个列表项。
你在itemBuilder中对details数组调用map转换后通过.toList()得到的是List<ListTile>类型(即组件列表),并非单个Widget,和闭包上下文要求的返回类型Widget不匹配,因此抛出类型错误。
你之前单独运行map相关代码没有报错,是因为当时map生成的组件列表是传给了Column、ListView默认构造函数这类接收List<Widget>作为children参数的组件,参数类型匹配自然不会报错。

修复方案

根据你的实际业务需求,二选一即可:

方案1:按外层name分组展示

如果需要把同个name下的所有details归为一组,每组作为列表中的一个区块,直接把map生成的组件列表放到支持多子节点的容器组件(比如Column)中,让itemBuilder最终返回单个容器组件即可:

// 补全原代码缺失的数组闭合
final nameAndRollNo = [
  {
    'name': 'Name 1',
    'details': [
      {'Roll No.': 'F101', 'age': 20,},
    ]
  },
  {
    'name': 'Name 2',
    'details': [
      {'Roll No.': 'F102', 'age': 25,},
    ]
  },
];

ListView.builder(
  itemCount: nameAndRollNo.length,
  itemBuilder: (context, index) {
    final currentGroup = nameAndRollNo[index];
    final detailItems = currentGroup['details'] as List<Map<String, dynamic>>;
    // 返回单个Column组件,map生成的ListTile作为Column的子组件
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // 可选:展示分组标题
        Padding(
          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
          child: Text(
            currentGroup['name'] as String,
            style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
          ),
        ),
        ...detailItems.map((value) {
          return ListTile(
            leading: const Icon(Icons.person),
            title: const Text('Any Name'),
            subtitle: Text(value['Roll No.']),
            trailing: IconButton(
              icon: const Icon(Icons.delete),
              onPressed: () {
                // 编写删除逻辑
              },
            ),
          );
        })
      ],
    );
  },
)

方案2:平铺所有details为独立列表项

如果不需要分组,要把所有details里的条目展开成ListView中独立的行,就不要在itemBuilder里做map转换,提前把嵌套数据拍平成一维数组再构建列表:

final nameAndRollNo = [
  {
    'name': 'Name 1',
    'details': [
      {'Roll No.': 'F101', 'age': 20,},
    ]
  },
  {
    'name': 'Name 2',
    'details': [
      {'Roll No.': 'F102', 'age': 25,},
    ]
  },
];

// 提前拍平嵌套的details数据
final flatDetailList = nameAndRollNo.expand((group) {
  return group['details'] as List<Map<String, dynamic>>;
}).toList();

ListView.builder(
  itemCount: flatDetailList.length,
  itemBuilder: (context, index) {
    final value = flatDetailList[index];
    // 直接返回单个ListTile,符合返回类型要求
    return ListTile(
      leading: const Icon(Icons.person),
      title: const Text('Any Name'),
      subtitle: Text(value['Roll No.']),
      trailing: IconButton(
        icon: const Icon(Icons.delete),
        onPressed: () {
          // 编写删除逻辑
        },
      ),
    );
  },
)
开发注意

所有懒加载列表类组件(ListView.builder/GridView.builder/SliverList.builder等)的itemBuilder回调,永远只接收单个Widget作为返回值,不能直接返回组件数组。map转换得到的组件列表,只能传给组件的children类型参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 08:06:20