带间隔项的列表
如何创建带有间隔或扩展项的列表
也许你想创建一个所有列表项均匀分布的列表,使这些项能够占用可见空间。例如,下图中四个项目均匀分布,“项 0”在顶部,“项 3”在底部。
同时,你可能还希望在列表项无法完全显示时(例如设备太小、用户调整了窗口大小或项目数量超过了屏幕尺寸)允许用户滚动列表。
通常,你会使用 Spacer 来调整组件之间的间距,或者使用 Expanded 来拉伸组件以填充可用空间。然而,这些解决方案在可滚动组件内部是无法使用的,因为它们需要一个有限的高度约束。
本方案演示了如何使用 LayoutBuilder 和 ConstrainedBox 在有足够空间时均匀分布列表项,并在空间不足时允许用户滚动,具体步骤如下:
- 添加一个带有
SingleChildScrollView的LayoutBuilder。 - 在
SingleChildScrollView中添加一个ConstrainedBox。 - 创建一个带有间隔项的
Column。
1. 添加一个 LayoutBuilder 和 SingleChildScrollView
#
首先创建一个 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')),
],
),
),
),
);
},
);
互动示例
#此示例展示了一个在 Column 中均匀分布的列表。当项目无法完全放入屏幕时,列表可以上下滚动。项目数量由变量 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))),
);
}
}