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

Flutter ListView嵌套GridView.builder无法懒加载问题咨询

问题根因

GridView无法懒加载的核心原因是你配置了shrinkWrap: true + 非独立滚动物理特性:
开启shrinkWrap后,GridView会预先计算所有子项的总高度来适配外层ListView的滚动容器,不会按需渲染可见范围内的子项,必然会一次性构建全部网格元素。你单独使用GridView.builder时没有开启shrinkWrap,所以懒加载表现正常。

解决方案1(最优,性能最佳):改用CustomScrollView + Sliver组件,完全兼容ValueListenableBuilder

你认为Sliver无法配合ValueListenableBuilder实现自动刷新是认知误区,ValueListenableBuilder可以包裹任何Sliver组件,改造后代码示例如下:

CustomScrollView(
  slivers: <Widget>[
    // 原有ListView中除了GridView之外的其他组件,用SliverToBoxAdapter包裹即可
    SliverToBoxAdapter(
      child: /* 其他非网格内容 */,
    ),
    // 第一个网格组件
    ValueListenableBuilder<List<MyObject>?>(
      valueListenable: xyz,
      builder: (BuildContext context, List<MyObject>? myList, Widget? child) {
        return SliverGrid.builder(
          itemCount: myList?.length ?? 0,
          gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
            childAspectRatio: uiConfig.getPosterAspectRatio(2 / 3.5),
            maxCrossAxisExtent: uiConfig.getPosterSize(),
            crossAxisSpacing: 5,
            mainAxisSpacing: 10,
          ),
          itemBuilder: (BuildContext context, int index) {
            final item = myList![index];
            return CustomWidget(item);
          },
        );
      },
    ),
    // 第二个网格组件同理配置即可
    ValueListenableBuilder<List<MyObject>?>(
      valueListenable: xyz2,
      builder: (context, myList2, child) {
        return SliverGrid.builder(
          itemCount: myList2?.length ?? 0,
          gridDelegate: /* 对应网格配置 */,
          itemBuilder: (context, index) => CustomWidget2(myList2![index]),
        );
      },
    )
  ],
)

该方案完全保留ValueListenableBuilder的自动刷新能力,所有子项都走CustomScrollView的统一懒加载逻辑,不会一次性构建全部元素,性能最优。

解决方案2(临时兼容,不改动原有ListView结构)

如果你坚持要保留外层ListView的嵌套结构,可以给GridView设置固定可视高度,关闭shrinkWrap,示例代码如下:

ListView(
  children: <Widget>[
    SizedBox(
      // 设置GridView在页面中的固定展示高度,可根据业务需求调整
      height: 500,
      child: ValueListenableBuilder(
        builder: (BuildContext context, List<MyObject>? myList, Widget? child) {
          return GridView.builder(
            itemCount: myList?.length ?? 0,
            // 移除shrinkWrap: true配置
            // 保留默认滚动物理特性,允许GridView内部独立滚动
            gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
              childAspectRatio: uiConfig.getPosterAspectRatio(2 / 3.5),
              maxCrossAxisExtent: uiConfig.getPosterSize(),
              crossAxisSpacing: 5,
              mainAxisSpacing: 10,
            ),
            itemBuilder: (BuildContext context, int index) {
              final item = myList![index];
              return CustomWidget(item);
            },
          );
        },
        valueListenable: xyz,
      ),
    ),
    buildGridView2(),
  ],
)

该方案的缺点是会出现嵌套滚动,用户需要滚动完GridView内部内容才能继续滚动外层ListView,使用体验不如方案1。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 14:57:03