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

Flutter中如何将GridView的CircularProgressIndicator显示在网格下方?

解决Flutter GridView中CircularProgressIndicator显示位置错误的问题

你当前的问题是把加载指示器当成了GridView的最后一个网格项,导致它被网格布局约束,显示在网格内部。要把它移到GridView下方,需要调整布局结构,将指示器和GridView拆分为两个独立组件,而非网格项的一部分。

修正思路

  • 移除itemCount中的+1,让GridView仅渲染商品列表
  • 将GridView与指示器放入垂直布局容器,让指示器固定在GridView下方
  • 通过加载状态变量控制指示器的显示/隐藏

代码实现

方案一:Column + Expanded(推荐,简单直接)

利用Expanded让GridView占满剩余空间,指示器自然位于底部:

Widget buildCatalog(List<Product> product, bool isLoading) => Column(
  children: [
    Expanded(
      child: GridView.builder(
        gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
          maxCrossAxisExtent: 300,
          childAspectRatio: MediaQuery.of(context).size.width * 1.22 /
              MediaQuery.of(context).size.height,
          crossAxisSpacing: 10,
          mainAxisSpacing: 10,
        ),
        controller: sController,
        itemCount: product.length, // 移除+1,仅渲染商品
        itemBuilder: (context, index) {
          final media = product[index].media?.map((e) => e.toJson()).toList();
          final photo = media?[0]['links']['local']['thumbnails']['350'];
          final productItem = product[index];
          return GestureDetector(
            onTap: () {},
            child: Container(
              child: Column(
                children: <Widget>[
                  InkWell(
                    child: Container(
                      margin: EdgeInsets.only(top: 5),
                      child: Image.network(photo ?? ''),
                    ),
                  ),
                  SizedBox(height: 10),
                  Text(
                    '${productItem.name}\n',
                    textAlign: TextAlign.center,
                    maxLines: 2,
                    overflow: TextOverflow.ellipsis,
                    style: TextStyle(fontSize: 14),
                  ),
                  SizedBox(height: 8),
                  Text('${productItem.price} ₸',
                      textAlign: TextAlign.start,
                      style: TextStyle(fontSize: 20, color: Colors.red)),
                  SizedBox(height: 5),
                  buildButton(index, productItem.id),
                ],
              ),
            ),
          );
        },
      ),
    ),
    // 加载指示器固定在GridView下方
    if (isLoading)
      Padding(
        padding: EdgeInsets.symmetric(vertical: 16),
        child: const Center(child: CircularProgressIndicator()),
      ),
  ],
);

方案二:CustomScrollView(适配复杂滚动场景)

如果需要更灵活的滚动效果,可以将GridView作为Sliver组件,通过SliverToBoxAdapter添加底部指示器:

Widget buildCatalog(List<Product> product, bool isLoading) => CustomScrollView(
  controller: sController,
  slivers: [
    SliverGrid(
      gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
        maxCrossAxisExtent: 300,
        childAspectRatio: MediaQuery.of(context).size.width * 1.22 /
            MediaQuery.of(context).size.height,
        crossAxisSpacing: 10,
        mainAxisSpacing: 10,
      ),
      delegate: SliverChildBuilderDelegate(
        (context, index) {
          final media = product[index].media?.map((e) => e.toJson()).toList();
          final photo = media?[0]['links']['local']['thumbnails']['350'];
          final productItem = product[index];
          return GestureDetector(
            onTap: () {},
            child: Container(
              child: Column(
                children: <Widget>[
                  InkWell(
                    child: Container(
                      margin: EdgeInsets.only(top: 5),
                      child: Image.network(photo ?? ''),
                    ),
                  ),
                  SizedBox(height: 10),
                  Text(
                    '${productItem.name}\n',
                    textAlign: TextAlign.center,
                    maxLines: 2,
                    overflow: TextOverflow.ellipsis,
                    style: TextStyle(fontSize: 14),
                  ),
                  SizedBox(height: 8),
                  Text('${productItem.price} ₸',
                      textAlign: TextAlign.start,
                      style: TextStyle(fontSize: 20, color: Colors.red)),
                  SizedBox(height: 5),
                  buildButton(index, productItem.id),
                ],
              ),
            ),
          );
        },
        childCount: product.length,
      ),
    ),
    // 底部加载指示器
    if (isLoading)
      SliverToBoxAdapter(
        child: Padding(
          padding: EdgeInsets.symmetric(vertical: 16),
          child: const Center(child: CircularProgressIndicator()),
        ),
      ),
  ],
);

注意事项

  • 新增的isLoading参数需要在父组件中维护,请求数据时设为true,加载完成后设为false
  • 给指示器添加Padding可以避免紧贴GridView,提升视觉舒适度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 03:01:01