帶有間距的清單
有時你可能希望建立一個所有清單項目之間均勻分布的清單,讓這些項目能夠佔據可見空間。例如,下圖中的四個項目就被均勻分布,「Item 0」在最上方,「Item 3」在最下方。

同時,當清單項目無法完全顯示時,你可能還希望讓使用者可以捲動清單。這可能是因為裝置螢幕太小、使用者調整了視窗大小,或是項目數量超過了螢幕可容納的範圍。

通常,你可以使用 [Spacer][Spacer] 來調整元件(Widgets)之間的間距,或使用 Expanded 來讓元件展開填滿可用空間。然而,這些解決方案在可捲動元件(Scrolling Widgets)內部並不可行,因為它們需要有限的高度約束。
本教學將示範如何使用 LayoutBuilder 與 ConstrainedBox,在有足夠空間時讓清單項目均勻分布,而在空間不足時允許使用者捲動,步驟如下:
- 新增一個帶有
SingleChildScrollView的LayoutBuilder。 - 在
SingleChildScrollView內加入ConstrainedBox。 - 建立一個具有間距項目的
Column。
1. 新增一個帶有 SingleChildScrollView 的 LayoutBuilder
#首先,建立一個 LayoutBuilder。你需要提供一個帶有兩個參數的 builder 回呼函式:
- 由
LayoutBuilder提供的BuildContext。 - 父元件的 [
BoxConstraints][BoxConstraints]。
在本教學中,你不會使用 BuildContext,但你會在下一步用到 [BoxConstraints][BoxConstraints]。
在 builder 函式內,回傳一個 SingleChildScrollView。這個元件可確保子元件即使在父容器太小時,也能夠被捲動顯示。
LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(child: Placeholder());
},
);2. 在SingleChildScrollView中加入ConstrainedBox
#在這個步驟中,將 ConstrainedBox 作為 SingleChildScrollView 的子元件(child)加入。
ConstrainedBox 元件(Widget)會對其子元件施加額外的限制。
請透過設定 minHeight 參數為 LayoutBuilder 限制中的 maxHeight 來配置這個限制。
這樣可以確保子元件 會被限制為最小高度等於 LayoutBuilder 限制所提供的可用空間, 也就是 [BoxConstraints][BoxConstraints] 的最大高度。
LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: Placeholder(),
),
);
},
);然而,你不需要設定 maxHeight 參數, 因為你需要允許子元件(child)可以大於 LayoutBuilder 的大小, 以防清單項目無法完全顯示於螢幕上。
3. 建立具有間距的 Column
#最後,將 Column 作為 ConstrainedBox 的子元件(child)。
為了讓項目之間平均分配間距, 請將 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][Spacer] 元件(Widget)來調整項目之間的間距,
或者如果你希望某個元件(Widget)比其他元件佔用更多空間,則可以使用 Expanded 元件(Widget)。
為此,你必須將 Column 包裹在 IntrinsicHeight 元件(Widget)中,
這樣會強制 Column 元件(Widget)以最小高度自我調整,
而不是無限擴展。
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))),
);
}
}
(/cookbook/lists/scrolling) [BoxConstraints]: https://api.flutter.dev/flutter/rendering/BoxConstraints-class.html