如何正确使用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
相关产品推荐
相关产品推荐

