我想在另一个小部件中有一个ListView
,当我FutureBuilder
包装在Column
中时,以便进行简单的Row
。我收到此错误:
The following assertion was thrown during performLayout():
I/flutter (13816): RenderFlex children have non-zero flex but incoming height constraints are unbounded.
I/flutter (13816): When a column is in a parent that does not provide a finite height constraint, for example, if it is
I/flutter (13816): in a vertical scrollable, it will try to shrink-wrap its children along the vertical axis. Setting a
I/flutter (13816): flex on a child (e.g. using Expanded) indicates that the child is to expand to fill the remaining
I/flutter (13816): space in the vertical direction.
I/flutter (13816): These two directives are mutually exclusive. If a parent is to shrink-wrap its child, the child
I/flutter (13816): cannot simultaneously expand to fit its parent.
I/flutter (13816): Consider setting mainAxisSize to MainAxisSize.min and using FlexFit.loose fits for the flexible
I/flutter (13816): children (using Flexible rather than Expanded). This will allow the flexible children to size
I/flutter (13816): themselves to less than the infinite remaining space they would otherwise be forced to take, and
I/flutter (13816): then will cause the RenderFlex to shrink-wrap the children rather than expanding to fit the maximum
I/flutter (13816): constraints provided by the parent.
I/flutter (13816): If this message did not help you determine the problem, consider using debugDumpRenderTree():
我的代码:
class ActivityShowTicketReplies extends StatefulWidget {
final Map<String, dynamic> ticketData;
ActivityShowTicketReplies({@required this.ticketData});
@override
State<StatefulWidget> createState() => ActivityShowTicketRepliesState();
}
class ActivityShowTicketRepliesState extends State<ActivityShowTicketReplies> {
TicketsTableData get _ticket => TicketsTableData.fromJson(json.decode(widget.ticketData.values.toList()[0][0].toString()));
@override
Widget build(BuildContext context) {
return ScopedModel(
model: CounterModel(),
child: Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
body: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0),
child: RaisedButton(
color: Colors.indigo,
onPressed: () => BlocProvider.of<AppPagesBloc>(context).dispatch(FragmentNavigateEvent(routeName: FRAGMENT_NEW_TICKET)),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(50.0)),
child: Container(
child: Text(
'new ticket',
style: AppTheme(context).caption().copyWith(color: Colors.white),
),
),
),
),
],
),
FutureBuilder(
future: Provider.of<TicketRepliesTableDao>(context).find(ticketId: _ticket.id),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
final List<TicketRepliesTableData> ticketReplies = snapshot.data;
if (ticketReplies.isNotEmpty) {
return Column(
children: <Widget>[
Card(
clipBehavior: Clip.antiAlias,
color: Colors.grey[50],
margin: EdgeInsets.all(10.0),
child: InkWell(
child: Stack(
children: <Widget>[
Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: ListTile(
title: Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0),
child: Text(
'subject',
style: AppTheme(context).caption().copyWith(fontFamily: 'ShabnamBold'),
),
),
subtitle: Text(
_ticket.subject,
style: AppTheme(context).caption(),
),
),
),
Container(
height: 30.0,
margin: EdgeInsets.zero,
width: double.infinity,
color: Colors.grey[200],
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
],
),
),
],
),
Align(
alignment: Alignment.topLeft,
child: Container(
margin: EdgeInsets.only(top: 10.0),
constraints: BoxConstraints(
minWidth: 70.0,
),
height: 20.0,
width: 70.0,
decoration: BoxDecoration(
color: Colors.green[200],
borderRadius: BorderRadius.only(
topRight: Radius.circular(5.0),
bottomRight: Radius.circular(5.0),
)),
child: Center(
child: Text(
'status',
style: AppTheme(context).overLine().copyWith(fontFamily: 'ShabnamBold', color: Colors.black),
),
)),
),
],
),
onTap: () {},
),
),
Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
return Card(
clipBehavior: Clip.antiAlias,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
Text(
ticketReplies[index].createdAt,
style: AppTheme(context).caption().copyWith(fontFamily: 'ShabnamLight'),
),
],
),
ListTile(
title: Text(ticketReplies[index].reply),
),
],
),
),
);
},
itemCount: ticketReplies.length,
),
),
],
);
} else {
return Center(
child: Text(
'there isn't any reply message',
style: AppTheme(context).caption(),
),
);
}
} else {
return _loader(context, 'no reply');
}
} else
return _loader(context, Strings.pleaseWait);
},
),
],
),
),
),
);
}
Widget _loader(BuildContext context,String message) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
ColorLoader3(
radius: 25.0,
dotRadius: 5.0,
),
Padding(
padding: const EdgeInsets.all(3.0),
child: Text(
Strings.pleaseWait,
style: AppTheme(context).caption().copyWith(color: Colors.red[900]),
),
),
],
));
}
}
将您的Column
包裹在Expanded
或SizedBox
(带有一些height
)中,如下所示:
Expanded(
child: Column(...)
)
或
SizedBox(
height: 200, // Some height
child: Column(...),
)
请注意,
Flex
类或子类(如Column
)不应该是其他Flex
类的子类,它们的父类需要是Flexible
类型(即继承它,像Expanded
),否则,Flex
类是无限的(并且无法计算剩余空间),这不会直接导致问题,直到另一个子类尝试计算和/或填充空间。
解释
如何用另一个Expanded
包装一个Column > Expanded
来解决错误。
RenderFlex Unbounded Error
收到"RenderFlex children have non-zero flex but incoming height constraints are unbounded"
错误的常见嵌套列扩展层次结构:
Screen
→ Column
→ Column
→ Expanded → ERROR
发生了什么事情:
Screen
↓ constraint ↓ (Screen)
Column
Text_A (fixed height: no constraint needed) → OK
Column
↓ constraint ↓ (unbounded)
Text_B (fixed height) → OK
Expanded: calc. height = unbounded - Text_B → ERROR
在布局期间,Column
执行(按顺序):
- 在无限空间中的固定高度(即零/零弹性因子)小部件布局,然后...
- 弹性因子大小的小部件,计算父项的剩余空间(即传入约束)和固定大小的小部件
以上Text_A
是固定高度的。它不使用布局的传入约束。
不过,Expanded
是一个弹性因子小部件,在布置固定大小的项目后,根据剩余空间调整自己的大小。 这需要传入约束(父大小)来执行减法:
parent size (constraint) - fixed-items size = remaining space
第一个Column
从设备屏幕获取约束(通过Scaffold
等提供)。
但是,第二个Column
(嵌套的)被布置在无限的空间中。
无法计算剩余空间:
unbounded - Text_B = unbounded (error)
为什么嵌套Column
是无限的?
Screen
→ Column
→ Column
→ Expanded
复制自Column
SDK 源文档的步骤 1:
/// 1. Layout each child with a null or zero flex factor (e.g., those that are not
/// [Expanded]) with unbounded vertical constraints
第二个,嵌套Column
:
- 是
Column
的孩子(显然是第一个),并且... - 具有零或零弯曲因子
第二点很容易错过/看不到,但Column
不是一个弹性因子小部件。
正在检查开发工具包源代码...
Column
扩展了Flex
类。
Flex
,没有flex
场/弯曲系数。 只有Flexible
类及其子类是弹性因子小部件。
因此,第 2Column
以无界约束布局,因为它不是弹性因子小部件。 这些无界约束用于布局Text_B
小部件(固定大小或空弹性因子小部件),然后Expanded
尝试计算剩余空间。 当尝试使用无界约束计算剩余空间时....
unbounded - Text_B = unbounded (error)
🔥Expanded
爆炸 🔥
Flexible
要说:Flexible
,是具有flex
字段/因子的弹性因子小部件。
Expanded
和Spacer
是Flexible
(我知道的)唯一的子班。
所以Expanded
、Spacer
和Flexible
是唯一的弹性因子小部件和
Flexible != Flex
修复 - 添加边界
修复小部件树:
Screen
→ Column
→ Expanded ← new
→ Column
→ Expanded → OK
为什么这有效...
Screen
↓ constraint ↓
Column
Text_A ↑ fixed-size ↑
↓ constraint ↓ (calculated: Screen height - Text_A height)
Expanded_A
↓ constraint ↓ (Screen - Text_A)
Column
Text_B ↑ fixed-size ↑
Expanded_B: calc. height = (Screen - Text_A) - Text_B = remaining space → OK
在这种情况下... 在固定项目布局(Text_A
)后,计算Expanded_A
的剩余空间:
parent size (screen) - fixed-items (Text_A) = remaining space
现在Expanded_A
有定义的空间量。
Expanded_A
提供其大小供子级使用,Column
计算布置Text_B
后的剩余Expanded_B
空间。
parent size - fixed-items = remaining space
↓
(Screen - Text_A) - (Text_B) = remaining space for Expanded_B
现在所有弹性因子相对大小的小部件(即Expanded_A
Expanded_B
)有界约束来计算它们的布局大小。
请注意,您可以在此处与Expanded
互换使用Flexible
。 它以与Expanded
相同的方式计算剩余空间。 它只是不强迫孩子们适应它的大小,所以如果他们愿意,他们可以更小。
复制/粘贴代码操作:
不行
/// Unbounded constraint: NOT OK
class RenderFlexUnboundedPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Column(
children: [
Text('Column > Column > Text_A'),
Expanded(
child: Text('Column > Column > Expanded_A')) // explosions
],
)
],
),
);
}
}
还行
/// Constraints provided: OK
class RenderFlexPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Text('Column > Text_A'),
Expanded( // Expanded_A
child: Column(
children: [
Text('Column > Expanded_A > Column > Text_B'),
Expanded( // Expanded_B
child: Text('Column > Expanded_A > Column > Expanded_B'))
],
),
)
],
),
);
}
}
如果要解决此问题Render Flex
请尝试:
Scaffold(
body: SingleChildScrollView(
child: SizedBox(
height: MediaQuery.of(context).size.height,
child: Column(
children: [
将columns
mainAxisSize
设置为min可以在SingleChildScrollView
的情况下解决,因为没有人承认这一点。
这种方法永远不会让我失望:
Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus finibus luctus tortor id pulvinar. Donec sollicitudin, dui vitae aliquam tristique, eros risus commodo enim, eget lobortis arcu velit ac arcu. "),
Text("Nunc tristique, ex ut volutpat feugiat, nulla nibh iaculis lectus, laoreet auctor justo tellus quis mi. Praesent ut interdum sem. Donec eget finibus augue, et vehicula elit. Praesent eu euismod arcu, eu maximus tellus. Ut diam est, sodales nec enim a, pharetra lobortis erat."),
]
)
)
就我而言,发生这种情况是因为我没有使用Expanded
小部件。然而,这也无助于取得成果。相反,我将SizedBox
与height
属性一起使用,如下所示:
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
height: MediaQuery.of(context).size.height,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
这很容易解决我的问题。
我想提供另一种解决方案,因为我只需要自己克服这个问题。对于上下文,这是引发此错误的小部件的过度简化结构:
Container
child: Column
children: Column, Spacer, Row
就我而言,我希望Container
与其中的内容一起扩展。最初,我为此容器定义了高度和宽度,但由于我希望它动态扩展,因此删除了这些约束。然后引发错误:
"RenderFlex 子项具有非零弯曲,但传入的高度约束是无限的">
我的问题是行之间的Spacer
。前Column
的子项试图无限扩展(因此"非零弹性"),因为Spacer
将每个子项推到其父项的垂直边界。这通常不是问题,但是对于间隔条将子项推到父项上没有限制。这是因为他们的父级,第一个Column
,也试图扩展,因为Container
没有被赋予高度或宽度属性。
我的解决方法是简单地将Spacer
替换为具有有限高度的SizedBox
:
Container
child: Column
children: Column, SizedBox(height: 10), Row