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

Flutter中创建可展开ListView的问题与报错排查

解决Flutter中ExpansionTile嵌套列表不显示的问题

看起来你遇到的是Flutter中嵌套滚动组件的经典布局约束问题——错误提示里的Vertical viewport was given unbounded height已经说得很清楚了:当你在一个可滚动的父组件(比如外层的ListView)里嵌套另一个垂直滚动组件(比如内层的ListView.builder)时,内层组件会试图占用无限的垂直空间,导致布局计算失败,最终组件无法正常显示。

下面给你两种可行的解决方案,你可以根据自己的需求选择:

方案一:用Column替代内层ListView(适合子项数量较少的场景)

你的当前代码其实已经在尝试这种思路了——通过_buildList生成子项列表,再用Column包裹。这种方式的好处是简单直接,不需要处理滚动冲突,而且对于少量子项来说性能足够。

你可以稍微优化一下布局,让UI更美观:

List<Widget> _buildList(int keyIndex) {
  return List.generate(data[dataKeys[keyIndex]].length, (i) {
    final item = data[dataKeys[keyIndex]][i];
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      child: Row(
        children: <Widget>[
          const CircleAvatar(
            child: Icon(Icons.verified_user),
            radius: 20.0,
          ),
          const SizedBox(width: 12), // 添加间距,避免内容挤在一起
          Expanded(child: Text(item[0])), // 让文本自动换行,避免溢出
          Text(item[1]),
        ],
      ),
    );
  });
}

方案二:给内层ListView添加约束(适合子项数量较多的场景)

如果你坚持要用ListView.builder(比如子项数量动态变化且可能很多),只需要给内层的ListView添加两个关键属性,就能解决高度无限的问题:

  • shrinkWrap: true:让ListView仅占用子项实际需要的高度,而不是试图填满父容器
  • physics: NeverScrollableScrollPhysics():禁用内层ListView的滚动功能,因为你需要的是非滚动列表,同时避免和外层ListView的滚动行为冲突

修改后的代码示例:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: const Text("Expense Monitor"),
    ),
    body: ListView.builder(
      itemCount: dataKeys.length,
      itemBuilder: (BuildContext context, int keyIndex) {
        return Card(
          child: ExpansionTile(
            title: Text(getFullDate(dataKeys[keyIndex])),
            children: <Widget>[
              ListView.builder(
                shrinkWrap: true,
                physics: const NeverScrollableScrollPhysics(),
                itemCount: data[dataKeys[keyIndex]].length,
                itemBuilder: (context, i) {
                  final item = data[dataKeys[keyIndex]][i];
                  return Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    child: Row(
                      children: <Widget>[
                        const CircleAvatar(
                          child: Icon(Icons.verified_user),
                          radius: 20.0,
                        ),
                        const SizedBox(width: 12),
                        Expanded(child: Text(item[0])),
                        Text(item[1]),
                      ],
                    ),
                  );
                },
              )
            ],
          ),
        );
      },
    ),
  );
}

两种方案都能解决你遇到的问题,选哪种取决于你的子项数量和性能需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:52:59