布局组件详解

布局组件是 Flutter 应用的基础,理解如何使用它们来构建复杂的用户界面至关重要。本教程将详细介绍 Flutter 中最常用的布局组件。

重要提示:Flutter 3.27+ 引入了 Row 和 Column 的 spacing 属性,Flutter 3.28+ 进一步优化了布局性能和 API。
📚 学习建议:在深入学习布局组件之前,建议先了解 Flutter 布局系统原理,包括约束模型、布局流程和性能优化原则。

1. Container 容器组件

Container 是最常用的布局组件之一,它是一个多功能组合 Widget,可以包含子 Widget、设置内边距、外边距、装饰等。

📐 Container 渲染效果

margin (外边距)
padding (内边距)
child 内容区域
margin
padding
child

核心属性

属性 类型 说明
alignment AlignmentGeometry 子组件的对齐方式
padding EdgeInsetsGeometry 内边距
margin EdgeInsetsGeometry 外边距
decoration BoxDecoration 装饰(背景、边框等)
width/height double 宽度和高度
constraints BoxConstraints 尺寸约束
transform Matrix4 变换矩阵

使用示例

// 基本 Container
Container(
  padding: const EdgeInsets.all(16),
  margin: const EdgeInsets.symmetric(horizontal: 10),
  decoration: BoxDecoration(
    color: Colors.blue,
    borderRadius: BorderRadius.circular(8),
    boxShadow: [
      BoxShadow(
        color: Colors.black.withOpacity(0.2),
        blurRadius: 8,
        spreadRadius: 2,
      ),
    ],
  ),
  child: const Text(
    'Hello, Container!',
    style: TextStyle(color: Colors.white),
  ),
)

// 带约束的 Container
Container(
  constraints: const BoxConstraints(
    minWidth: 100,
    maxWidth: 200,
    minHeight: 50,
    maxHeight: 100,
  ),
  decoration: BoxDecoration(
    color: Colors.orange,
    borderRadius: BorderRadius.circular(12),
  ),
  child: const Center(
    child: Text(
      '约束容器',
      style: TextStyle(color: Colors.white),
    ),
  ),
)

// 带变换的 Container
Container(
  padding: const EdgeInsets.all(20),
  decoration: BoxDecoration(
    color: Colors.purple,
    borderRadius: BorderRadius.circular(16),
  ),
  transform: Matrix4.rotationZ(0.1),
  child: const Text(
    '旋转容器',
    style: TextStyle(color: Colors.white),
  ),
)
技巧:使用 const 构造函数可以提高性能,Container 在 Flutter 3.27 中更加高效。

2. Row 行布局

Row Widget 在水平方向上排列子 Widget,是构建水平布局的基础组件。

📐 Row 渲染效果 (水平排列)

A
B
C

← 水平方向 (mainAxis) →

核心属性

属性 类型 说明
mainAxisAlignment MainAxisAlignment 主轴对齐方式
crossAxisAlignment CrossAxisAlignment 交叉轴对齐方式
mainAxisSize MainAxisSize 主轴尺寸
verticalDirection VerticalDirection 垂直方向
textDirection TextDirection 文本方向
textBaseline TextBaseline 文本基线

使用示例

// 基本 Row
Row(
  children: const [
    Text('A'),
    Text('B'),
    Text('C'),
  ],
)

// 主轴居中对齐
Row(
  mainAxisAlignment: MainAxisAlignment.center,
  children: const [
    Text('左'),
    Text('中'),
    Text('右'),
  ],
)

// 交叉轴居中对齐
Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  crossAxisAlignment: CrossAxisAlignment.center,
  children: [
    Container(
      width: 50,
      height: 30,
      color: Colors.red,
    ),
    Container(
      width: 50,
      height: 60,
      color: Colors.green,
    ),
    Container(
      width: 50,
      height: 90,
      color: Colors.blue,
    ),
  ],
)

// 使用 Spacing(Flutter 3.27+ 新特性)
Row(
  spacing: 10,
  children: [
    const Icon(Icons.star, color: Colors.yellow),
    const Icon(Icons.star, color: Colors.yellow),
    const Icon(Icons.star, color: Colors.yellow),
    const Icon(Icons.star_half, color: Colors.yellow),
    const Icon(Icons.star_border, color: Colors.yellow),
  ],
)

// Expanded 和 Flexible
Row(
  children: [
    Expanded(
      flex: 2,
      child: Container(
        color: Colors.blue,
        height: 100,
        child: const Center(child: Text('2倍')),
      ),
    ),
    Expanded(
      flex: 1,
      child: Container(
        color: Colors.red,
        height: 100,
        child: const Center(child: Text('1倍')),
      ),
    ),
  ],
)
技巧:在 Flutter 3.27+ 中,使用 spacing 属性替代 SizedBox 可以让代码更简洁。

3. Column 列布局

Column Widget 在垂直方向上排列子 Widget,与 Row 类似,只是方向相反。

📐 Column 渲染效果 (垂直排列)

A
B
C

↓ 垂直方向 (mainAxis) ↓

使用示例

// 基本 Column
Column(
  children: const [
    Text('第一行'),
    Text('第二行'),
    Text('第三行'),
  ],
)

// 完整的表单布局
Column(
  crossAxisAlignment: CrossAxisAlignment.stretch,
  children: [
    const Text(
      '登录表单',
      style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
    ),
    const SizedBox(height: 20),
    const TextField(
      decoration: InputDecoration(
        labelText: '用户名',
        border: OutlineInputBorder(),
        prefixIcon: Icon(Icons.person),
      ),
    ),
    const SizedBox(height: 16),
    const TextField(
      decoration: InputDecoration(
        labelText: '密码',
        border: OutlineInputBorder(),
        prefixIcon: Icon(Icons.lock),
      ),
      obscureText: true,
    ),
    const SizedBox(height: 20),
    ElevatedButton(
      onPressed: () {},
      style: ElevatedButton.styleFrom(
        padding: const EdgeInsets.symmetric(vertical: 16),
      ),
      child: const Text('登录'),
    ),
  ],
)

// 使用 Spacing(Flutter 3.27+)
Column(
  spacing: 16,
  children: [
    Container(
      height: 50,
      color: Colors.red,
    ),
    Container(
      height: 50,
      color: Colors.green,
    ),
    Container(
      height: 50,
      color: Colors.blue,
    ),
  ],
)

4. Stack 堆叠布局

Stack Widget 允许子 Widget 重叠,可以用来实现复杂的层叠效果,如图片上的文字覆盖、悬浮按钮等。

📐 Stack 渲染效果 (层叠排列)

底层
中层
顶层

子 Widget 按顺序层叠,后面的在上层

核心属性

属性 类型 说明
alignment AlignmentGeometry 未定位子组件的对齐方式
textDirection TextDirection 文本方向
fit StackFit 子组件如何适应堆叠
clipBehavior Clip 裁剪行为

使用示例

// 基本 Stack
Stack(
  alignment: Alignment.center,
  children: [
    Container(
      width: 200,
      height: 200,
      color: Colors.blue,
    ),
    Container(
      width: 150,
      height: 150,
      color: Colors.red,
    ),
    Container(
      width: 100,
      height: 100,
      color: Colors.yellow,
    ),
  ],
)

// 使用 Positioned 定位
Stack(
  children: [
    // 背景图片
    Container(
      width: 200,
      height: 200,
      decoration: const BoxDecoration(
        image: DecorationImage(
          image: NetworkImage('https://via.placeholder.com/200'),
          fit: BoxFit.cover,
        ),
        borderRadius: BorderRadius.all(Radius.circular(10)),
      ),
    ),
    // 标题在顶部
    Positioned(
      top: 10,
      left: 10,
      right: 10,
      child: Container(
        padding: const EdgeInsets.all(8),
        color: Colors.black54,
        child: const Text(
          '图片标题',
          style: TextStyle(color: Colors.white),
        ),
      ),
    ),
    // 右下角按钮
    Positioned(
      bottom: 10,
      right: 10,
      child: FloatingActionButton(
        mini: true,
        onPressed: () {},
        child: const Icon(Icons.edit),
      ),
    ),
  ],
)

// IndexedStack(只显示一个子组件)
IndexedStack(
  index: _selectedIndex,
  children: [
    Container(color: Colors.red),
    Container(color: Colors.green),
    Container(color: Colors.blue),
  ],
)
技巧:使用 Align Widget 可以更灵活地控制 Stack 中未定位子组件的位置。

5. SizedBox 尺寸盒

SizedBox 是一个简单的固定尺寸盒子,常用于在布局中添加间距或限制子组件大小。

📐 SizedBox 渲染效果

固定间距 (height: 20)

第一项
SizedBox(height: 20)
第二项

固定尺寸 (width: 200, height: 100)

固定大小 200px 100px

扩展到父组件大小 (SizedBox.expand)

充满父容器

使用示例

// 添加间距
Column(
  children: [
    const Text('第一项'),
    const SizedBox(height: 20),
    const Text('第二项'),
  ],
)

// 限制子组件大小
SizedBox(
  width: 200,
  height: 100,
  child: Container(
    color: Colors.blue,
    child: const Center(child: Text('固定大小')),
  ),
)

// 扩展到父组件大小
SizedBox.expand(
  child: Container(
    color: Colors.green,
    child: const Center(child: Text('充满父容器')),
  ),
)

// 收缩到子组件大小
SizedBox.shrink(
  child: Container(
    color: Colors.orange,
    child: const Text('收缩到子组件大小'),
  ),
)

6. Expanded 和 Flexible

Expanded 和 Flexible 用于在 Row 或 Column 中控制子组件如何分配可用空间。

📐 Expanded 和 Flexible 渲染效果

Expanded 等分空间

Expanded(1)
Expanded(1)
Expanded(1)

Expanded 按比例分配 (1:2:3)

flex: 1
flex: 2
flex: 3

Flexible 允许子组件小于可用空间

Flexible
(width: 50)
Flexible
(自动)

Expanded vs Flexible (tight vs loose)

Expanded
(tight)
Flexible
(loose)

Expanded 强制子组件填满空间,Flexible 允许子组件小于可用空间

Expanded

// 等分空间
Row(
  children: [
    Expanded(
      child: Container(
        color: Colors.red,
        height: 100,
      ),
    ),
    Expanded(
      child: Container(
        color: Colors.blue,
        height: 100,
      ),
    ),
  ],
)

// 按比例分配空间
Row(
  children: [
    Expanded(
      flex: 1,
      child: Container(
        color: Colors.red,
        height: 100,
      ),
    ),
    Expanded(
      flex: 2,
      child: Container(
        color: Colors.blue,
        height: 100,
      ),
    ),
    Expanded(
      flex: 3,
      child: Container(
        color: Colors.green,
        height: 100,
      ),
    ),
  ],
)

Flexible

// Flexible 允许子组件小于可用空间
Row(
  children: [
    Flexible(
      flex: 1,
      child: Container(
        width: 50,
        color: Colors.red,
        height: 100,
      ),
    ),
    Flexible(
      flex: 2,
      child: Container(
        color: Colors.blue,
        height: 100,
      ),
    ),
  ],
)

// Flexible 的 fit 参数
Row(
  children: [
    Flexible(
      fit: FlexFit.tight,
      flex: 1,
      child: Container(
        color: Colors.red,
        height: 100,
      ),
    ),
    Flexible(
      fit: FlexFit.loose,
      flex: 1,
      child: Container(
        width: 50,
        color: Colors.blue,
        height: 100,
      ),
    ),
  ],
)
注意:Expanded 是 Flexible 的一个特例,相当于 Flexible(fit: FlexFit.tight)。

7. Spacer 间隔器

Spacer 在 Row 或 Column 中创建可调整的空隙,将其他子组件推向两侧。

📐 Spacer 渲染效果

将组件推到两端

Spacer()

多个 Spacer 创建等分间距

🏠
Spacer()
🔍
Spacer()
⚙️

Spacer 的 flex 参数 (2:1)

Spacer(flex: 2)
Spacer(flex: 1)

使用示例

// 将组件推到两端
Row(
  children: const [
    Text('左'),
    Spacer(),
    Text('右'),
  ],
)

// 多个 Spacer 创建等分间距
Row(
  children: const [
    Icon(Icons.home),
    Spacer(),
    Icon(Icons.search),
    Spacer(),
    Icon(Icons.settings),
  ],
)

// Spacer 的 flex 参数
Row(
  children: [
    const Text('左'),
    const Spacer(flex: 2),
    const Text('中'),
    const Spacer(flex: 1),
    const Text('右'),
  ],
)

8. SafeArea 安全区域

SafeArea 确保内容不会被系统 UI(如状态栏、刘海屏、底部导航栏)遮挡。

使用示例

// 基本 SafeArea
SafeArea(
  child: Container(
    color: Colors.blue,
    child: const Text('安全区域内的内容'),
  ),
)

// 自定义安全区域
SafeArea(
  top: true,
  bottom: true,
  left: false,
  right: false,
  minimum: const EdgeInsets.all(16),
  child: Container(
    color: Colors.blue,
    child: const Text('自定义安全区域'),
  ),
)

// 在整个应用中使用
MaterialApp(
  builder: (context, child) {
    return SafeArea(
      child: child!,
    );
  },
  home: const MyHomePage(),
)

9. AspectRatio 宽高比

AspectRatio 强制子组件保持指定的宽高比。

📐 AspectRatio 渲染效果

1:1 正方形

1:1 aspectRatio: 1.0

16:9 视频比例

16:9 aspectRatio: 16/9

4:3 照片比例

4:3 aspectRatio: 4/3

常见宽高比对比

1:1
4:3
16:9
21:9

使用示例

// 1:1 正方形
AspectRatio(
  aspectRatio: 1.0,
  child: Container(
    color: Colors.blue,
    width: double.infinity,
    child: const Center(child: Text('1:1')),
  ),
)

// 16:9 视频比例
AspectRatio(
  aspectRatio: 16 / 9,
  child: Container(
    color: Colors.green,
    width: double.infinity,
    child: const Center(child: Text('16:9')),
  ),
)

// 4:3 照片比例
AspectRatio(
  aspectRatio: 4 / 3,
  child: Container(
    color: Colors.red,
    width: double.infinity,
    child: const Center(child: Text('4:3')),
  ),
)

10. Card 卡片组件

Card 是 Material Design 风格的卡片组件,用于组织相关内容。

📐 Card 渲染效果

基本 Card

卡片标题

卡片内容区域

带阴影的 Card

高阴影卡片

elevation: 8

圆角 Card

圆角卡片

borderRadius: 16

图片卡片示例

🖼️

精美图片卡片

这是一个带有图片的卡片组件示例,展示了 Card 的布局能力。

标签1 标签2

Card 核心特性

圆角边框
阴影效果
点击反馈
内容裁剪

使用示例

// 基本 Card
Card(
  child: Padding(
    padding: const EdgeInsets.all(16.0),
    child: Column(
      children: const [
        Text('卡片标题', style: TextStyle(fontSize: 18)),
        SizedBox(height: 8),
        Text('卡片内容'),
      ],
    ),
  ),
)

// 带阴影的 Card
Card(
  elevation: 8,
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(12),
  ),
  child: const Padding(
    padding: EdgeInsets.all(16.0),
    child: Text('带阴影的卡片'),
  ),
)

// 点击效果的 Card
Card(
  elevation: 2,
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(12),
  ),
  child: InkWell(
    onTap: () {
      print('Card 被点击');
    },
    child: const Padding(
      padding: EdgeInsets.all(16.0),
      child: Text('可点击的卡片'),
    ),
  ),
)

// 图片卡片
Card(
  clipBehavior: Clip.antiAlias,
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(12),
  ),
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      Image.network(
        'https://via.placeholder.com/300x200',
        fit: BoxFit.cover,
      ),
      const Padding(
        padding: EdgeInsets.all(16.0),
        child: Text('图片卡片', style: TextStyle(fontSize: 18)),
      ),
    ],
  ),
)

🔀 布局组件选择流程图

开始布局
需要什么布局?
水平排列
Row
垂直排列
Column
重叠布局
Stack
完成布局

📊 布局组件对比

Flutter 布局组件对比表
组件 方向 子组件数量 使用场景
Container 单组件 1 装饰、约束、变换
Row 水平 多个 水平排列组件
Column 垂直 多个 垂直排列组件
Stack 重叠 多个 层叠组件
Expanded 扩展 1 占满可用空间
Flexible 灵活 1 灵活占用空间

布局最佳实践

  • 使用 Flutter 3.27+ 的 spacing 属性简化布局代码
  • 合理使用 const 构造函数提高性能
  • 避免过度嵌套,优先考虑提取子 Widget
  • 使用 Padding Widget 而不是 Container 来添加间距
  • 在需要约束的地方使用 ConstrainedBox
  • 使用 LayoutBuilder 响应父组件的约束
  • 使用 MediaQuery 适配不同屏幕尺寸
进阶学习:掌握基础布局后,可以学习 CustomSingleChildLayout 和 CustomMultiChildLayout 来创建自定义布局。