Flutter處理Spacing(元件間距)

前言

在 Flutter 的 Column 中,有多種方式可以處理子 widget 之間的間隔

使用 SizedBox

SizedBox 是最常用的方法之一,可以在子 widget 之間添加固定大小的間隔。

Column(
  children: [
    Text('Item 1'),
    SizedBox(height: 16), // 添加固定的垂直間隔
    Text('Item 2'),
  ],
)
  • 優點:簡單直觀,適合固定大小的間隔。
  • 缺點:需要手動為每個間隔都添加一個 SizedBox。

 使用 Spacer

Spacer 可以在子 widget 之間添加彈性間隔。

Column(
  children: [
    Text('Item 1'),
    Spacer(), // 添加彈性間隔
    Text('Item 2'),
  ],
)
  • 優點:按比例分配間隔空間,適合需要彈性布局的情況。
  • 缺點:無法指定具體的間隔大小。

使用 Padding

在每個子 widget 外層添加 Padding,指定外邊距來實現間隔。

Column(
  children: [
    Padding(
      padding: EdgeInsets.only(bottom: 16), // 下方間隔
      child: Text('Item 1'),
    ),
    Text('Item 2'),
  ],
)
  • 優點:可以靈活設置方向上的間隔。
  • 缺點:需要在每個子 widget 外層包裹 Padding。

使用 Divider

Divider 是用於分隔的 widget,可以在 Column 中添加水平分隔線並調整間隔。

Column(
  children: [
    Text('Item 1'),
    Divider(height: 16, color: Colors.grey), // 間隔線和間距
    Text('Item 2'),
  ],
)
  • 優點:適合需要分隔線的場景。
  • 缺點:無法完全自定義間隔空間。

使用 MainAxisAlignment

效果等同Figma中的 Auto Layout 中的 Gap-Auto

如果間隔是均勻分佈的,可以使用 Column 的 mainAxisAlignment 屬性。

Column(
  mainAxisAlignment: MainAxisAlignment.spaceBetween, // 均勻分佈
  children: [
    Text('Item 1'),
    Text('Item 2'),
  ],
)
  • 優點:簡潔,適合均勻分佈的情況。
  • 缺點:無法設置不同的間隔大小。

[補充] 常用的 MainAxisAlignment 值:

  • MainAxisAlignment.start:子 widget 從開始排列。
  • MainAxisAlignment.center:子 widget 居中排列。
  • MainAxisAlignment.spaceBetween:子 widget 之間的間隔相等,首尾不留空。
  • MainAxisAlignment.spaceAround:子 widget 之間和邊界之間的間隔相等。
  • MainAxisAlignment.spaceEvenly:子 widget 之間和邊界之間的間隔均等。

使用 Wrap

當子 widget 數量或大小不固定時,可以使用 Wrap 代替 Column,並設置 spacing 屬性。

Wrap(
  spacing: 16, // 水平方向的間隔
  runSpacing: 16, // 垂直方向的間隔
  children: [
    Text('Item 1'),
    Text('Item 2'),
  ],
)
  • 優點:靈活處理多行、多列的布局。
  • 缺點:不完全等同於 Column,適用於更動態的布局。

使用 Custom MultiChildLayout

當間隔邏輯非常複雜時,可以使用自定義的 MultiChildLayoutDelegate 來控制每個子 widget 的位置和間隔。

class CustomLayoutDelegate extends MultiChildLayoutDelegate {
  @override
  void performLayout(Size size) {
    // 自定義布局邏輯
  }

  @override
  bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) => true;
}

CustomMultiChildLayout(
  delegate: CustomLayoutDelegate(),
  children: [
    LayoutId(id: 'item1', child: Text('Item 1')),
    LayoutId(id: 'item2', child: Text('Item 2')),
  ],
)
  • 優點:提供最大自由度。
  • 缺點:實現和維護較為繁瑣。

如何選擇要使用哪種方式去調整間距

  • 固定間隔:使用 SizedBox。
  • 彈性間隔:使用 Spacer。
  • 需要分隔線:使用 Divider。
  • 需要靈活布局:使用 Wrap。
  • 需要統一控制間隔:使用 Padding 或 mainAxisAlignment。
方法描述優點缺點適用場景
SizedBox在子 widget 之間添加固定大小的間隔。簡單直觀,適合固定大小的間隔。需要手動為每個間隔都添加一個 SizedBox固定大小的間隔需求。
Spacer在子 widget 之間添加彈性間隔。按比例分配間隔空間,適合需要彈性布局的情況。無法指定具體的間隔大小。彈性間隔需求,例如均勻分佈的場景。
Padding在每個子 widget 外層添加 Padding,指定外邊距來實現間隔。可以靈活設置方向上的間隔。需要在每個子 widget 外層包裹 Padding需要控制個別 widget 的間隔方向。
Divider添加水平分隔線並調整間隔。適合需要分隔線的場景,能提供視覺分割效果。無法完全自定義間隔空間,且多用於有視覺分隔需求的場景。需要分隔線的界面。
MainAxisAlignment使用 ColumnmainAxisAlignment 設置均勻的間隔。簡潔,適合均勻分佈的情況。無法設置不同的間隔大小,僅適用於簡單均勻分佈場景。均勻分佈間隔的場景。
Wrap使用 Wrap 並設置 spacingrunSpacing 來處理間隔。靈活處理多行、多列的布局。不完全等同於 Column,適用於更動態的布局。動態內容或多行、多列的布局場景。
Custom Layout使用 CustomMultiChildLayout 並自定義 MultiChildLayoutDelegate 處理間隔邏輯。提供最大自由度,可實現複雜布局和間隔需求。實現和維護較為繁瑣,僅適合高定制場景。複雜布局和間隔需求。