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

SingleChildScrollView嵌套两个ListView.builder引发应用冻结问题

问题原因

应用冻结的直接诱因是两个ListView.builder均未设置itemCount参数。
ListView.builder默认采用懒加载机制,未指定itemCount时会判定列表项数量为无限大;同时你给列表设置了shrinkWrap: true,该属性要求列表一次性计算所有子项的总高度来确定自身布局尺寸,布局阶段会陷入无限计算子项的死循环,直接阻塞UI线程,最终表现为页面打开后无响应、应用冻结。

修复方案

最小改动修复

只需要给两个ListView.builder补充明确的itemCount参数,传入每个列表实际需要渲染的条目总数即可解决死循环问题,示例代码如下:

body: SingleChildScrollView(
  physics: const ScrollPhysics(),
  child: Column(
    children: <Widget>[
      ListView.builder(
        physics: const NeverScrollableScrollPhysics(),
        shrinkWrap: true,
        itemCount: firstList.length, // 替换为第一个列表的实际数据长度
        itemBuilder: (context, index) {
          return Container(
            padding: const EdgeInsets.all(10),
            height: 75,
            child: Row(
              children: <Widget>[
                // 补充第一个列表的项内容
              ],
            ),
          );
        }
      ),
      ListView.builder(
        physics: const NeverScrollableScrollPhysics(),
        shrinkWrap: true,
        itemCount: secondList.length, // 替换为第二个列表的实际数据长度
        itemBuilder: (context, index) {
          return Container(
            padding: const EdgeInsets.all(10),
            height: 75,
            child: Row(
              children: <Widget>[
                // 补充第二个列表的项内容
              ],
            ),
          );
        }
      ),
    ],
  ),
),

更优性能实现

上述最小修复虽然能解决冻结问题,但shrinkWrap: true会让列表一次性渲染所有子项,完全失去懒加载能力,当列表数据量较大时会出现卡顿、内存占用高的问题。如果要实现同一个滚动域下的多列表效果,更推荐使用CustomScrollView配合Sliver组件实现,无需禁用子列表滚动、无需设置shrinkWrap,原生支持懒加载,性能更好:

body: CustomScrollView(
  slivers: <Widget>[
    // 第一个分组列表
    SliverList(
      delegate: SliverChildBuilderDelegate(
        (context, index) {
          return Container(
            padding: const EdgeInsets.all(10),
            height: 75,
            child: Row(
              children: <Widget>[
                // 第一个列表的项内容
              ],
            ),
          );
        },
        childCount: firstList.length, // 第一个列表条目总数
      ),
    ),
    // 第二个分组列表
    SliverList(
      delegate: SliverChildBuilderDelegate(
        (context, index) {
          return Container(
            padding: const EdgeInsets.all(10),
            height: 75,
            child: Row(
              children: <Widget>[
                // 第二个列表的项内容
              ],
            ),
          );
        },
        childCount: secondList.length, // 第二个列表条目总数
      ),
    ),
  ],
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 00:27:19