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

如何正确使用FractionallySizedBox创建自适应大小的Card列表?

解决FractionallySizedBox在ListView中高度无限的问题

我之前也踩过一模一样的坑!核心问题出在:ListView是垂直滚动组件,它给子项的高度约束是无限的(h<=Infinity),而FractionallySizedBox的heightFactor必须依赖父级的确定高度才能计算自身尺寸——父级高度无限的话,它根本算不出自己该有多高,自然就会抛出那个错误。

下面给你几个可行的解决方案,你可以根据自己的场景选择:

方案一:直接基于屏幕尺寸设置相对大小(适合容器是全屏的场景)

如果你的ListView是占满整个屏幕的,直接用MediaQuery获取屏幕尺寸,给Card设置固定的百分比大小就行,简单粗暴还好用:

@override
Widget build(BuildContext context) {
  final screenSize = MediaQuery.of(context).size;
  return Scaffold(
    appBar: AppBar(title: Text(widget.title)),
    body: ListView.builder(
      itemCount: 3,
      itemBuilder: (context, i) {
        return Center( // 让Card在ListView中居中显示
          child: Card(
            elevation: 10,
            child: SizedBox(
              width: screenSize.width * 0.8, // 宽度为屏幕的80%
              height: screenSize.height * 0.3, // 高度为屏幕的30%
              child: Row(
                children: <Widget>[
                  Padding(
                    padding: EdgeInsets.all(10.0),
                    child: GestureDetector(
                      onTap: () => print("tapped"),
                      child: Container(
                        width: 100.0,
                        height: 100.0,
                        decoration: BoxDecoration(
                          color: Colors.red,
                          borderRadius: BorderRadius.all(Radius.circular(75.0)),
                          boxShadow: [BoxShadow(blurRadius: 7.0, color: Colors.black)],
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
        );
      },
    ),
  );
}

方案二:用LayoutBuilder获取父容器约束(适合父容器不是全屏的场景)

如果你的ListView嵌套在某个有固定尺寸的父组件里,用LayoutBuilder可以获取到父容器的准确约束,再基于这个约束设置Card的大小:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: Text(widget.title)),
    body: LayoutBuilder(
      builder: (context, parentConstraints) {
        return ListView.builder(
          itemCount: 3,
          itemBuilder: (context, i) {
            return Center(
              child: FractionallySizedBox(
                widthFactor: 0.8, // 宽度为父容器的80%
                child: SizedBox(
                  height: parentConstraints.maxHeight * 0.3, // 高度为父容器的30%
                  child: Card(
                    elevation: 10,
                    child: Row(
                      children: <Widget>[
                        // 你的子组件代码
                      ],
                    ),
                  ),
                ),
              ),
            );
          },
        );
      },
    ),
  );
}

这里不用FractionallySizedBox的heightFactor是因为ListView的item高度约束还是无限的,所以我们直接用父容器的确定高度来计算Card的高度。

方案三:用AspectRatio实现固定宽高比(适合需要保持宽高比例的场景)

如果你的需求是Card的宽高比固定(比如宽是父容器的80%,高度是宽度的1/3),用AspectRatio会更灵活:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: Text(widget.title)),
    body: ListView.builder(
      itemCount: 3,
      itemBuilder: (context, i) {
        return Center(
          child: FractionallySizedBox(
            widthFactor: 0.8, // 宽度为父容器的80%
            child: AspectRatio(
              aspectRatio: 3 / 1, // 宽高比3:1,可根据需求调整
              child: Card(
                elevation: 10,
                child: Row(
                  children: <Widget>[
                    // 你的子组件代码
                  ],
                ),
              ),
            ),
          ),
        );
      },
    ),
  );
}

总结一下

FractionallySizedBox的核心是依赖父级的确定约束,当父级是ListView这种给子项无限高度约束的组件时,你必须先给它一个有确定尺寸的父级(比如SizedBox、Container),或者直接基于已知的确定约束(屏幕尺寸、LayoutBuilder的约束)来设置尺寸,这样它才能正常工作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 06:52:39