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

如何让GridView子项高度自适应其中最高子项的高度?

解决GridView子项高度自适应最高子项的问题

原生GridView的SliverGridDelegateWithFixedCrossAxisCount不支持自动让所有子项高度统一为最高子项的高度,以下是两种可行的解决方案:

方法一:手动计算最大子项高度

通过先布局子项获取高度,再将最大高度设置为mainAxisExtent,实现统一高度:

  1. 定义变量存储最大高度和子项的全局Key:
double _maxItemHeight = 0;
List<GlobalKey> _itemKeys = [];
  1. 初始化阶段生成Key并延迟计算最大高度:
@override
void initState() {
  super.initState();
  _itemKeys = List.generate(prizes.length, (index) => GlobalKey());
  // 等待首次布局完成后计算高度
  WidgetsBinding.instance.addPostFrameCallback((_) {
    _calculateMaxHeight();
  });
}

void _calculateMaxHeight() {
  double maxHeight = 0;
  for (var key in _itemKeys) {
    final renderBox = key.currentContext?.findRenderObject() as RenderBox?;
    if (renderBox != null) {
      final height = renderBox.size.height;
      if (height > maxHeight) {
        maxHeight = height;
      }
    }
  }
  setState(() {
    _maxItemHeight = maxHeight;
  });
}
  1. 修改GridView代码,绑定Key并使用计算出的最大高度:
GridView.builder(
  shrinkWrap: true,
  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2,
    mainAxisExtent: _maxItemHeight, // 用计算出的最大高度替代固定值
    crossAxisSpacing: 8,
    mainAxisSpacing: 8,
  ),
  itemCount: prizes.length,
  itemBuilder: (context, index){
    return Card(
      key: _itemKeys[index], // 绑定全局Key用于获取高度
      elevation: 3.0,
      shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(10.0)),
      color: Colors.white,
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          children: [
            Stack(
              children: [
                Image.asset(prizes[index]["image"]),
              ],
            ),
            Padding(
              padding: const EdgeInsets.only(top: 10.0),
              child: Text(
                prizes[index]["name"],
                style: const TextStyle(fontWeight: FontWeight.bold),
              ),
            ),
            Padding(
              padding: const EdgeInsets.only(top: 8.0),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children:  [
                  Text(
                    prizes[index]["cost"].toString(),
                    style: const TextStyle(fontWeight: FontWeight.normal),
                  ),
                  Padding(
                    padding: const EdgeInsets.only(left : 4.0),
                    child: SizedBox(
                        width: 14,
                        height: 14,
                        child: svg),
                  ),
                ],
              ),
            ),
            Padding(
              padding: const EdgeInsets.only(top: 10),
              child: ElevatedButton(
                style: ButtonStyle(
                    backgroundColor: MaterialStateProperty.all(Colors.blue),
                    shape: MaterialStateProperty.all<RoundedRectangleBorder>(
                        RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(8.0),
                        )
                    )
                ),
                onPressed: () async {},
                child:  Padding(
                  padding: EdgeInsets.all(15.0),
                  child: Text(AppLocalizations.of(context)!.riscuoti,
                    style: TextStyle(
                        fontSize: 16
                    ),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  },
)

注意:这种方法会有首次布局后高度调整的闪烁,适合数据量不大的场景。

方法二:使用第三方库实现自适应高度网格

借助flutter_staggered_grid_view库,可以更简洁地实现同一行子项高度统一:

  1. 添加依赖到pubspec.yaml:
dependencies:
  flutter_staggered_grid_view: ^0.7.0
  1. 替换原生GridView为StaggeredGridView.count:
StaggeredGridView.count(
  shrinkWrap: true,
  crossAxisCount: 2,
  mainAxisSpacing: 8,
  crossAxisSpacing: 8,
  // 让每个子项占满一列宽度,自动适配行内最高高度
  staggeredTiles: List.generate(prizes.length, (index) => const StaggeredTile.fit(1)),
  children: prizes.map((prize) {
    return Card(
      elevation: 3.0,
      shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(10.0)),
      color: Colors.white,
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          children: [
            Stack(
              children: [
                Image.asset(prize["image"]),
              ],
            ),
            Padding(
              padding: const EdgeInsets.only(top: 10.0),
              child: Text(
                prize["name"],
                style: const TextStyle(fontWeight: FontWeight.bold),
              ),
            ),
            Padding(
              padding: const EdgeInsets.only(top: 8.0),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children:  [
                  Text(
                    prize["cost"].toString(),
                    style: const TextStyle(fontWeight: FontWeight.normal),
                  ),
                  Padding(
                    padding: const EdgeInsets.only(left : 4.0),
                    child: SizedBox(
                        width: 14,
                        height: 14,
                        child: svg),
                  ),
                ],
              ),
            ),
            Padding(
              padding: const EdgeInsets.only(top: 10),
              child: ElevatedButton(
                style: ButtonStyle(
                    backgroundColor: MaterialStateProperty.all(Colors.blue),
                    shape: MaterialStateProperty.all<RoundedRectangleBorder>(
                        RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(8.0),
                        )
                    )
                ),
                onPressed: () async {},
                child:  Padding(
                  padding: EdgeInsets.all(15.0),
                  child: Text(AppLocalizations.of(context)!.riscuoti,
                    style: TextStyle(
                        fontSize: 16
                    ),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }).toList(),
)

StaggeredTile.fit(1)会自动让同一行的所有子项高度匹配最高的那个,无需手动计算,体验更流畅。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 14:41:44