带间隔项目的列表
也许你希望创建一个列表,其中所有列表项都均匀分布,以便这些项占据可见空间。例如,下图中的四个项均匀分布,“项 0”在顶部,“项 3”在底部。
同时,你可能希望当列表项不适合时允许用户滚动浏览列表,这可能是因为设备太小、用户调整了窗口大小,或者项目数量超出了屏幕大小。
通常,你使用 Spacer
来调整小部件之间的间距,或者使用 Expanded
来扩展小部件以填充可用空间。但是,这些解决方案在可滚动小部件中是不可行的,因为它们需要一个有限的高度约束。
本教程演示了如何使用 LayoutBuilder
和 ConstrainedBox
,通过以下步骤在有足够空间时均匀地间隔列表项,并在空间不足时允许用户滚动
- 添加一个带
SingleChildScrollView
的LayoutBuilder
。 - 在
SingleChildScrollView
中添加一个ConstrainedBox
。 - 创建一个带间隔项目的
Column
。
1. 添加一个带 SingleChildScrollView
的 LayoutBuilder
#首先创建一个 LayoutBuilder
。你需要提供一个带两个参数的 builder
回调函数
LayoutBuilder
提供的BuildContext
。- 父小部件的
BoxConstraints
。
在本教程中,你不会使用 BuildContext
,但在下一步中你需要 BoxConstraints
。
在 builder
函数中,返回一个 SingleChildScrollView
。这个小部件确保子小部件可以滚动,即使父容器太小。
LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(child: Placeholder());
},
);
2. 在 SingleChildScrollView
中添加一个 ConstrainedBox
#在此步骤中,添加一个 ConstrainedBox
作为 SingleChildScrollView
的子级。
ConstrainedBox
小部件对其子级施加额外的约束。
通过将 minHeight
参数设置为 LayoutBuilder
约束的 maxHeight
来配置约束。
这确保子小部件被约束为具有一个最小高度,该高度等于 LayoutBuilder
约束提供的可用空间,即 BoxConstraints
的最大高度。
LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: Placeholder(),
),
);
},
);
但是,你不需要设置 maxHeight
参数,因为你需要允许子级大于 LayoutBuilder
大小,以防项目不适合屏幕。
3. 创建一个带间隔项目的 Column
#最后,添加一个 Column
作为 ConstrainedBox
的子级。
为了均匀地间隔项目,将 mainAxisAlignment
设置为 MainAxisAlignment.spaceBetween
。
LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ItemWidget(text: 'Item 1'),
ItemWidget(text: 'Item 2'),
ItemWidget(text: 'Item 3'),
],
),
),
);
},
);
或者,如果你希望某个小部件占据比其他小部件更多的空间,可以使用 Spacer
小部件来调整项目之间的间距,或者使用 Expanded
小部件。
为此,你必须用 IntrinsicHeight
小部件包装 Column
,这会强制 Column
小部件将自身调整为最小高度,而不是无限扩展。
LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: IntrinsicHeight(
child: Column(
children: [
ItemWidget(text: 'Item 1'),
Spacer(),
ItemWidget(text: 'Item 2'),
Expanded(child: ItemWidget(text: 'Item 3')),
],
),
),
),
);
},
);
互动示例
#此示例显示了一个在列中均匀间隔的项目列表。当项目不适合屏幕时,列表可以上下滚动。项目数量由变量 items
定义,更改此值以查看当项目不适合屏幕时会发生什么。
import 'package:flutter/material.dart';
void main() => runApp(const SpacedItemsList());
class SpacedItemsList extends StatelessWidget {
const SpacedItemsList({super.key});
@override
Widget build(BuildContext context) {
const items = 4;
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
cardTheme: CardThemeData(color: Colors.blue.shade50),
),
home: Scaffold(
body: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: List.generate(
items,
(index) => ItemWidget(text: 'Item $index'),
),
),
),
);
},
),
),
);
}
}
class ItemWidget extends StatelessWidget {
const ItemWidget({super.key, required this.text});
final String text;
@override
Widget build(BuildContext context) {
return Card(
child: SizedBox(height: 100, child: Center(child: Text(text))),
);
}
}