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

Flutter模态底部弹窗报错:Vertical viewport was given unbounded height

解决Flutter模态底部弹窗内嵌ListView的"Vertical viewport was given unbounded height"错误

这个错误的核心原因是:Column是垂直方向无约束的容器,而ListView默认会试图占据无限的垂直高度,两者组合触发了布局冲突。

你可以通过以下两种方式解决,推荐第二种(更适配底部弹窗的场景):

方法1:给ListView添加shrinkWrap: true

让ListView根据子项的总高度自动收缩自身尺寸,不再试图抢占无限空间:

ListView.builder(
  shrinkWrap: true, // 添加这一行
  physics: const ScrollPhysics(),
  itemCount: widget.user.myEvents!.length,
  // ... 其余代码不变
)

方法2:用Expanded包裹ListView

让ListView占据Column中除顶部标题外的剩余可用空间,保证列表在弹窗范围内滚动,这是底部弹窗场景下更稳定的方案:

_showModal(BuildContext context) {
  showModalBottomSheet(
      context: context,
      builder: (context) => Container(
          margin: const EdgeInsets.only(top: 10),
          child: Column(children: [
            Row(mainAxisAlignment: MainAxisAlignment.center, children: [
              Text('Select event',
                  style: Theme.of(context).textTheme.headlineMedium)
            ]),
            // 用Expanded包裹ListView
            Expanded(
              child: ListView.builder(
                  physics: const ScrollPhysics(),
                  itemCount: widget.user.myEvents!.length,
                  itemBuilder: (contex, index) {
                    return StreamBuilder(
                        stream: di
                            .gt<GetSingleEventUseCase>()
                            .call(widget.user.myEvents![index]),
                        builder: (context, snapshot) {
                          if (snapshot.hasData) {
                            return TileSettings(
                                title: snapshot.data!.first.eventName!,
                                leading: snapshot.data!.first.guestsid!
                                            .contains(widget.otherUser.uid) ||
                                        snapshot.data!.first.guestsid!
                                            .contains(widget.otherUser.uid)
                                    ? const Image(image: ticketLinear)
                                    : const Image(image: ticket),
                                onTap: () {},
                                trailing: const SizedBox.shrink());
                          } else {
                            return TileSettings(
                                title: 'No events',
                                leading: const Image(image: cross),
                                onTap: () {},
                                trailing: const SizedBox.shrink());
                          }
                        });
                  }),
            )
          ])));
}

两种方案的区别:

  • shrinkWrap: true适合列表项较少的场景,ListView会完全包裹所有子项;如果列表很长,可能会因一次性渲染所有子项导致性能问题。
  • Expanded会约束ListView在弹窗的可用高度内,列表超出部分可滚动,适配绝大多数底部弹窗的使用场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 18:42:25