颤振:"RenderFlex children have non-zero flex but incoming height constraints are unbounded"



我想在另一个小部件中有一个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包裹在ExpandedSizedBox(带有一些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

复制自ColumnSDK 源文档的步骤 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字段/因子的弹性因子小部件。

ExpandedSpacerFlexible(我知道的)唯一的子班。

所以ExpandedSpacerFlexible是唯一的弹性因子小部件和

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_AExpanded_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: [

columnsmainAxisSize设置为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小部件。然而,这也无助于取得成果。相反,我将SizedBoxheight属性一起使用,如下所示:

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

最新更新