在 Flutter 中,如何调整垂直布局,混合列和列表视图行为?
In Flutter, how can I have an adjusting vertical layout, a mix between column and listview behavior?
据我所知,Column 和 ListView 在用于基本根布局时都有非常不同的用法。
Column 在屏幕组件较少时使用(例如登录屏幕)。我们可以添加一些 Expanded 组件来调整中间的空白,这样当键盘可见时,屏幕会缩小以保持所有内容可见。
当屏幕有许多可能需要滚动的组件时,使用 ListView。我们不能在 ListView 中使用 Expanded 组件。使用ListView时,出现键盘不会改变空格,只会改变外部ListView的大小,而内部内容被滚动视图包裹。
现在的问题是,如果我想要这样的屏幕怎么办:
当所有内容的合并垂直大小不长于父级提供的可用高度配额(在本例中为屏幕高度)时,组件的行为类似于列内:扩展或收缩以填充根据 Expanded 设置的规则可用的空格。
当所有内容的合并垂直大小超过可用高度配额时,组件的行为就像在 ListView 中一样:所有可能展开的组件将缩小到它们的最小尺寸(忽略展开的),并且屏幕是可滚动的,因此用户可以看到下面屏幕的其余部分。
在 Flutter 中可以实现吗?怎么样?
编辑:根据 Reign 的评论,我从 SingleChildScrollView manual 中分离了一些代码,但如果它的子项包含 Expanded,它看起来仍然无法处理。
Widget columnRoot({
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.spaceBetween,
AssetImage backgroundImage,
List<Widget> children
}) =>
LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) =>
SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: backgroundImage,
fit: BoxFit.cover),
color: Colors.white
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: mainAxisAlignment,
children: children
),
)
)
)
);
Widget content(BuildContext context) => columnRoot(children: [
Container(color: Colors.red, height: 100.0),
Expanded(Container(color: Colors.green)), // without this line, there's no layout error
Container(color: Colors.blue, height: 100.0),
]);
错误:
RenderFlex children have non-zero flex but incoming height constraints are unbounded.
我添加了一些您可以测试的代码,并附有一些解释。
复制粘贴并运行代码
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: SingleChildScrollView( //Since setting it to scrollable, your widget Column with expanded children wont work as it supposed to be because it wont know its parent height
//Since its already scrollable `Expanded` will expand or shrink now based on it child widget (Expanded(child: SomeHeight widget)) refer: #10 example
child: IntrinsicHeight( //This will fix the expanded widget error
child: Container(
//Test remove this height
// height: 400, //But when you set its height before its parent scroll widget, `Expanded` will expand based on its available space
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.max,
children: [
Container(color: Colors.red, height: 100.0),
//#10
//Experiment with this
Expanded(
child: Container(
color: Colors.purple,
// height: 100.0, //initialized height, remove parent container height: 400
// child: Text("This is also considered as min height"),
),
),
Container(color: Colors.blue, height: 100.0),
],
),
),
),
),
),
);
}
}
据我所知,Column 和 ListView 在用于基本根布局时都有非常不同的用法。
Column 在屏幕组件较少时使用(例如登录屏幕)。我们可以添加一些 Expanded 组件来调整中间的空白,这样当键盘可见时,屏幕会缩小以保持所有内容可见。
当屏幕有许多可能需要滚动的组件时,使用 ListView。我们不能在 ListView 中使用 Expanded 组件。使用ListView时,出现键盘不会改变空格,只会改变外部ListView的大小,而内部内容被滚动视图包裹。
现在的问题是,如果我想要这样的屏幕怎么办:
当所有内容的合并垂直大小不长于父级提供的可用高度配额(在本例中为屏幕高度)时,组件的行为类似于列内:扩展或收缩以填充根据 Expanded 设置的规则可用的空格。
当所有内容的合并垂直大小超过可用高度配额时,组件的行为就像在 ListView 中一样:所有可能展开的组件将缩小到它们的最小尺寸(忽略展开的),并且屏幕是可滚动的,因此用户可以看到下面屏幕的其余部分。
在 Flutter 中可以实现吗?怎么样?
编辑:根据 Reign 的评论,我从 SingleChildScrollView manual 中分离了一些代码,但如果它的子项包含 Expanded,它看起来仍然无法处理。
Widget columnRoot({
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.spaceBetween,
AssetImage backgroundImage,
List<Widget> children
}) =>
LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) =>
SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: backgroundImage,
fit: BoxFit.cover),
color: Colors.white
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: mainAxisAlignment,
children: children
),
)
)
)
);
Widget content(BuildContext context) => columnRoot(children: [
Container(color: Colors.red, height: 100.0),
Expanded(Container(color: Colors.green)), // without this line, there's no layout error
Container(color: Colors.blue, height: 100.0),
]);
错误:
RenderFlex children have non-zero flex but incoming height constraints are unbounded.
我添加了一些您可以测试的代码,并附有一些解释。
复制粘贴并运行代码
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: SingleChildScrollView( //Since setting it to scrollable, your widget Column with expanded children wont work as it supposed to be because it wont know its parent height
//Since its already scrollable `Expanded` will expand or shrink now based on it child widget (Expanded(child: SomeHeight widget)) refer: #10 example
child: IntrinsicHeight( //This will fix the expanded widget error
child: Container(
//Test remove this height
// height: 400, //But when you set its height before its parent scroll widget, `Expanded` will expand based on its available space
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.max,
children: [
Container(color: Colors.red, height: 100.0),
//#10
//Experiment with this
Expanded(
child: Container(
color: Colors.purple,
// height: 100.0, //initialized height, remove parent container height: 400
// child: Text("This is also considered as min height"),
),
),
Container(color: Colors.blue, height: 100.0),
],
),
),
),
),
),
);
}
}