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

Flutter:SliverGrid在CustomScrollView内不显示及网格项总数量指定问题

解决SliverGrid在CustomScrollView中不显示及指定网格项数量的问题

我来帮你拆解下问题出在哪,以及怎么修复:

核心问题分析

你的代码有两个关键问题导致了空白页面和潜在的多余item问题:

  1. FutureBuilder放错位置了:你把FutureBuilder放在了每个网格item的构建逻辑里,这意味着每个item都会单独触发一次数据请求,而且SliverChildBuilderDelegate根本不知道要生成多少个item,自然无法渲染。
  2. 缺少childCount参数:SliverChildBuilderDelegate必须通过childCount明确告诉系统要生成多少个网格项,否则它会一直尝试生成item直到超出边界(但因为你没给数量,系统直接不渲染了)。

修复后的完整示例代码

// 先把获取数据的Future存成类成员变量,避免每次build都重新发起请求
late final Future<List<YourItemModel>> _items;

@override
void initState() {
  super.initState();
  _items = fetchDataFromApi(); // 这里是你的REST API请求方法
}

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: FutureBuilder<List<YourItemModel>>(
      future: _items,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          // 加载中:用SliverToBoxAdapter放加载提示,适配CustomScrollView的sliver结构
          return CustomScrollView(
            slivers: [
              SliverToBoxAdapter(
                child: Center(child: CircularProgressIndicator()),
              ),
            ],
          );
        } else if (snapshot.hasError) {
          // 请求失败:显示重试按钮
          return CustomScrollView(
            slivers: [
              SliverToBoxAdapter(
                child: Center(
                  child: TextButton(
                    onPressed: () {
                      setState(() {
                        _items = fetchDataFromApi(); // 重新请求
                      });
                    },
                    child: Text('Retry'),
                  ),
                ),
              ),
            ],
          );
        } else if (!snapshot.hasData || snapshot.data!.isEmpty) {
          // 没有数据:显示空状态
          return CustomScrollView(
            slivers: [
              SliverToBoxAdapter(
                child: Center(child: Text('No data found')),
              ),
            ],
          );
        } else {
          // 数据加载成功:构建正常的SliverGrid
          final itemList = snapshot.data!;
          return CustomScrollView(
            slivers: [
              SliverGrid(
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 2,
                ),
                delegate: SliverChildBuilderDelegate(
                  (BuildContext context, int index) {
                    // 直接用已加载好的数据构建网格项
                    final item = itemList[index];
                    return GridItem(item: item); // 把数据传给你的GridItem组件
                  },
                  // 关键:指定网格项的总数量,就是数据列表的长度
                  childCount: itemList.length,
                ),
              ),
            ],
          );
        }
      },
    ),
  );
}

关键修复点说明

  • 把FutureBuilder移到外层:让整个CustomScrollView等待数据加载完成后再渲染,而不是每个item单独等待。这样不仅避免了重复请求,还能统一处理加载、错误、空数据状态。
  • 添加childCount参数:通过childCount: itemList.length,明确告诉SliverGrid要生成的item数量和你的数据条数完全一致,再也不用担心生成多余的item。
  • Future存为类成员:把_items放在initState里初始化,而不是直接在build方法里创建,这样每次页面重建时不会重复发起API请求。

额外提示

如果你的GridItem需要处理单个item的异步操作(比如加载网络图片),那可以在GridItem内部使用FutureBuilder,而不是在SliverChildBuilderDelegate的层面。这样就不会影响整个SliverGrid的渲染逻辑啦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 11:49:05