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

Flutter中如何为水平ListView和GridView设置动态高度?

水平GridView布局效果

问题描述

当前使用固定高度225.h的Container包裹水平滚动的GridView,存在以下问题:

  • 嵌套在ListView中时,必须设置固定高度才能显示,移除高度后布局消失
  • 设备默认字体调大时,固定高度会导致布局错乱,需要实现动态高度的水平GridView
解决方案

方法1:用CustomScrollView替代嵌套ListView

如果页面整体是滚动布局,直接用CustomScrollView组合Sliver组件,从根源避免嵌套滚动视图的高度计算冲突:

CustomScrollView(
  slivers: [
    // 页面其他内容用SliverToBoxAdapter包裹
    SliverToBoxAdapter(
      child: Text("页面其他内容"),
    ),
    // 水平GridView对应的Sliver组件
    SliverToBoxAdapter(
      child: _buildHorizontalGridView(),
    ),
    // 其他页面内容组件
  ],
)

方法2:动态计算容器高度

因为你的GridView是垂直方向2列(crossAxisCount:2),可以基于单个Item的内部元素尺寸,加上padding、margin和间距,计算出容器的动态高度:

Widget _buildHorizontalGridView() {
  // 计算单个Item的实际高度:文本高度 + 上下padding + 底部margin
  final singleItemHeight = (15.sp + 6.h + 11.sp) + 10.h * 2 + 15.h;
  // 总高度 = 2列Item高度 + GridView上下padding + 垂直方向间距
  final totalHeight = singleItemHeight * 2 + 8.h * 2 + 16.0;

  return Container(
    width: double.infinity,
    padding: EdgeInsets.zero,
    height: totalHeight, // 动态计算的高度
    child: GridView.builder(
      scrollDirection: Axis.horizontal,
      primary: false,
      shrinkWrap: true,
      padding: EdgeInsets.only(left: 16.w, top: 8.h, right: 16.w),
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 2,
          childAspectRatio: 0.5,
          mainAxisSpacing: 16.0,
          crossAxisSpacing: 0.0),
      itemCount: drConsultationModelList.length,
      itemBuilder: (context, i) {
        // 原Item代码保持不变
        return Container(
          width: 210.w,
          margin: EdgeInsets.only(bottom: 15.h),
          padding: EdgeInsets.only(left: 16.w, bottom: 10.h, right: 20.h, top: 10.h),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(12.r),
            color: Colors.white,
            boxShadow: [
              BoxShadow(
                color: const Color(0x14000000),
                offset: const Offset(0.0, 4.0),
                blurRadius: 14.0,
                spreadRadius: 0.0,
              ),
            ],
          ),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.start,
            mainAxisSize: MainAxisSize.max,
            children: [
              Expanded(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(drConsultationModelList[i].tvTitle,
                        style: TextStyle(
                            fontFamily: fontInterSemibold,
                            fontSize: 15.sp,
                            color: blackes_1a1b25)),
                    SizedBox(height: 6.h),
                    Text(drConsultationModelList[i].tvSubTitle,
                        style: TextStyle(
                            fontFamily: fontInterRegular,
                            fontSize: 11.sp,
                            color: dark_silver_6a7382))
                  ],
                ),
              ),
              Stack(
                alignment: Alignment.center,
                children: [
                  Container(
                    height: 50.h,
                    width: 50.w,
                    decoration: BoxDecoration(
                      color: const Color(0xffe7f5f0),
                      borderRadius: BorderRadius.circular(8.r),
                    ),
                  ),
                  SvgPicture.asset(drConsultationModelList[i].imgLogo,
                      width: 34.w, height: 34.h, fit: BoxFit.fill),
                ],
              )
            ],
          ),
        );
      },
    ),
  );
}

方法3:用LayoutBuilder适配父容器约束

如果必须嵌套在ListView中,可通过LayoutBuilder获取父容器的约束条件,结合childAspectRatio反向计算高度:

LayoutBuilder(
  builder: (context, constraints) {
    final itemWidth = 210.w;
    // 根据childAspectRatio=0.5,反向计算Item高度:宽/高=0.5 → 高度=宽度*2
    final itemHeight = itemWidth * 2;
    // 总高度 = 2列Item高度 + GridView上下padding + 垂直间距
    final totalHeight = itemHeight * 2 + 8.h * 2 + 16.0;

    return Container(
      height: totalHeight,
      child: GridView.builder(
        // 原GridView参数保持不变
        scrollDirection: Axis.horizontal,
        primary: false,
        shrinkWrap: true,
        padding: EdgeInsets.only(left: 16.w, top: 8.h, right: 16.w),
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 2,
            childAspectRatio: 0.5,
            mainAxisSpacing: 16.0,
            crossAxisSpacing: 0.0),
        itemCount: drConsultationModelList.length,
        itemBuilder: (context, i) {
          // 原Item代码不变
          return ...;
        },
      ),
    );
  },
)

关键注意点

  • 保持shrinkWrap: true,让GridView根据子组件尺寸自动收缩
  • 关闭primary: false避免滚动冲突
  • 动态计算高度时要包含所有padding、margin和间距,防止内容被截断

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 11:05:16