Flutter 小白入门教程Flutter 小白入门教程
首页
学习指南
项目实战
Flutter 官网
编程指南
首页
学习指南
项目实战
Flutter 官网
编程指南
  • 入门基础

    • 📚 基础教程
    • 第1章 - 认识 Flutter
    • 第2章 - 环境搭建
    • 第3章 - Dart 语言基础
    • 第4章 - 第一个 Flutter 应用
    • 第5章 - Widget 基础
    • 第6章 - 布局系统
    • 第7章 - 状态管理入门
    • 第8章 - 页面导航
    • 第9章 - 资源管理
  • 进阶开发

    • 第10章 - 网络请求
    • 第11章 - 本地存储
    • 第12章 - 对话框与反馈
    • 第13章 - 列表进阶
    • 第14章 - 主题定制
    • 第15章 - 状态管理进阶
    • 第16章 - 动画入门
    • 第17章 - 常用第三方包
  • 调试与发布

    • 第18章 - 调试与性能优化
    • 第19章 - 打包与发布
  • 附录

    • 附录A - UI 框架与组件库推荐
    • 附录B - 项目结构最佳实践
    • 附录C - 国际化配置
    • 附录D - 权限处理

第6章 - 布局系统

嗨,朋友!我是长安。

学会了各种 Widget 后,下一个问题就是:怎么把它们整齐地排列起来? 这就需要用到 Flutter 的布局系统了。

🤔 布局的核心概念

Flutter 的布局思路很简单:用 Widget 包裹 Widget。

布局 Widget
    └── 子 Widget 1
    └── 子 Widget 2
    └── 子 Widget 3

常用的布局 Widget 分为两类:

类型Widget说明
单子布局Container、Center、SizedBox、Padding只能包含一个子 Widget
多子布局Row、Column、Stack、ListView、GridView可以包含多个子 Widget

📏 Row - 水平布局

Row 让子组件水平排列。

Row(
  children: [
    Container(width: 50, height: 50, color: Colors.red),
    Container(width: 50, height: 50, color: Colors.green),
    Container(width: 50, height: 50, color: Colors.blue),
  ],
)

效果:🟥 🟩 🟦 (从左到右排列)

主轴对齐 - mainAxisAlignment

Row(
  mainAxisAlignment: MainAxisAlignment.start,      // 靠左(默认)
  mainAxisAlignment: MainAxisAlignment.center,     // 居中
  mainAxisAlignment: MainAxisAlignment.end,        // 靠右
  mainAxisAlignment: MainAxisAlignment.spaceBetween, // 两端对齐
  mainAxisAlignment: MainAxisAlignment.spaceAround,  // 等间距
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,  // 完全等分
  children: [...],
)

图示:

start:        |🟥🟩🟦         |
center:       |    🟥🟩🟦    |
end:          |         🟥🟩🟦|
spaceBetween: |🟥    🟩    🟦|
spaceAround:  | 🟥  🟩  🟦 |
spaceEvenly:  |  🟥  🟩  🟦  |

交叉轴对齐 - crossAxisAlignment

Row(
  crossAxisAlignment: CrossAxisAlignment.start,   // 顶部对齐
  crossAxisAlignment: CrossAxisAlignment.center,  // 垂直居中(默认)
  crossAxisAlignment: CrossAxisAlignment.end,     // 底部对齐
  crossAxisAlignment: CrossAxisAlignment.stretch, // 拉伸填满
  children: [...],
)

📐 Column - 垂直布局

Column 让子组件垂直排列,用法和 Row 类似,只是方向变了。

Column(
  children: [
    Container(width: 50, height: 50, color: Colors.red),
    Container(width: 50, height: 50, color: Colors.green),
    Container(width: 50, height: 50, color: Colors.blue),
  ],
)

效果:

🟥
🟩
🟦

记忆技巧

  • Row 的主轴是水平方向,交叉轴是垂直方向
  • Column 的主轴是垂直方向,交叉轴是水平方向

🔄 Expanded 与 Flexible

当需要子组件按比例填充剩余空间时,使用 Expanded 或 Flexible。

Expanded - 填充剩余空间

Row(
  children: [
    Container(width: 50, height: 50, color: Colors.red),
    Expanded(  // 填充剩余空间
      child: Container(height: 50, color: Colors.green),
    ),
    Container(width: 50, height: 50, color: Colors.blue),
  ],
)

效果:🟥 ━━━━━🟩━━━━━ 🟦

flex 属性 - 按比例分配

Row(
  children: [
    Expanded(
      flex: 1,  // 占 1 份
      child: Container(height: 50, color: Colors.red),
    ),
    Expanded(
      flex: 2,  // 占 2 份
      child: Container(height: 50, color: Colors.green),
    ),
    Expanded(
      flex: 1,  // 占 1 份
      child: Container(height: 50, color: Colors.blue),
    ),
  ],
)

效果:红色占 25%,绿色占 50%,蓝色占 25%

📚 Stack - 层叠布局

Stack 让子组件重叠在一起,像扑克牌一样堆叠。

Stack(
  children: [
    // 底层
    Container(
      width: 200,
      height: 200,
      color: Colors.blue,
    ),
    // 中层
    Container(
      width: 150,
      height: 150,
      color: Colors.green,
    ),
    // 顶层
    Container(
      width: 100,
      height: 100,
      color: Colors.red,
    ),
  ],
)

Positioned - 绝对定位

在 Stack 中使用 Positioned 精确控制位置:

Stack(
  children: [
    Container(width: 300, height: 300, color: Colors.grey[200]),
    Positioned(
      top: 10,
      left: 10,
      child: Container(width: 50, height: 50, color: Colors.red),
    ),
    Positioned(
      bottom: 10,
      right: 10,
      child: Container(width: 50, height: 50, color: Colors.blue),
    ),
    Positioned.fill(  // 填满整个 Stack
      child: Center(
        child: Text('居中文字'),
      ),
    ),
  ],
)

📜 ListView - 列表布局

ListView 是可滚动的列表,当内容超出屏幕时会自动滚动。

基础用法

ListView(
  children: const [
    ListTile(title: Text('项目 1')),
    ListTile(title: Text('项目 2')),
    ListTile(title: Text('项目 3')),
    // ... 更多项目
  ],
)

ListView.builder - 动态列表(推荐)

当列表项很多时,使用 builder 按需创建,性能更好:

ListView.builder(
  itemCount: 100,  // 列表项数量
  itemBuilder: (context, index) {
    return ListTile(
      leading: CircleAvatar(child: Text('$index')),
      title: Text('项目 $index'),
      subtitle: Text('这是第 $index 项的描述'),
    );
  },
)

ListView.separated - 带分隔线

ListView.separated(
  itemCount: 20,
  itemBuilder: (context, index) {
    return ListTile(title: Text('项目 $index'));
  },
  separatorBuilder: (context, index) {
    return const Divider();  // 分隔线
  },
)

🔲 GridView - 网格布局

GridView 用于创建网格布局,如相册、商品列表等。

GridView.count(
  crossAxisCount: 3,  // 每行 3 个
  crossAxisSpacing: 10,  // 水平间距
  mainAxisSpacing: 10,   // 垂直间距
  padding: const EdgeInsets.all(10),
  children: List.generate(9, (index) {
    return Container(
      color: Colors.blue[(index + 1) * 100],
      child: Center(
        child: Text('$index', style: const TextStyle(color: Colors.white)),
      ),
    );
  }),
)

GridView.builder - 动态网格

GridView.builder(
  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2,      // 每行 2 个
    childAspectRatio: 1.5,  // 宽高比
    crossAxisSpacing: 10,
    mainAxisSpacing: 10,
  ),
  itemCount: 20,
  itemBuilder: (context, index) {
    return Card(
      child: Center(child: Text('Item $index')),
    );
  },
)

🎁 Wrap - 自动换行布局

当子组件超出一行时,Wrap 会自动换行,常用于标签列表。

Wrap(
  spacing: 8,         // 水平间距
  runSpacing: 8,      // 行间距
  children: [
    Chip(label: Text('Flutter')),
    Chip(label: Text('Dart')),
    Chip(label: Text('Widget')),
    Chip(label: Text('Layout')),
    Chip(label: Text('State')),
    Chip(label: Text('Navigation')),
  ],
)

效果:

[Flutter] [Dart] [Widget] [Layout]
[State] [Navigation]

📦 单子布局 Widget

Center - 居中

Center(
  child: Text('我会居中'),
)

Padding - 内边距

Padding(
  padding: const EdgeInsets.all(16),
  child: Text('我有内边距'),
)

SizedBox - 固定尺寸/间距

// 固定尺寸
SizedBox(
  width: 100,
  height: 100,
  child: Container(color: Colors.red),
)

// 作为间距
Column(
  children: [
    Text('上面'),
    SizedBox(height: 20),  // 20 像素垂直间距
    Text('下面'),
  ],
)

AspectRatio - 宽高比

AspectRatio(
  aspectRatio: 16 / 9,  // 16:9 的比例
  child: Container(color: Colors.blue),
)

🎯 布局实战示例

示例1:个人资料卡片

Card(
  margin: const EdgeInsets.all(16),
  child: Padding(
    padding: const EdgeInsets.all(16),
    child: Row(
      children: [
        // 头像
        const CircleAvatar(
          radius: 40,
          backgroundImage: NetworkImage('https://example.com/avatar.jpg'),
        ),
        const SizedBox(width: 16),
        // 信息
        Expanded(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text(
                '长安',
                style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 4),
              Text(
                'Flutter 开发者',
                style: TextStyle(color: Colors.grey[600]),
              ),
              const SizedBox(height: 8),
              const Wrap(
                spacing: 8,
                children: [
                  Chip(label: Text('Flutter')),
                  Chip(label: Text('Dart')),
                ],
              ),
            ],
          ),
        ),
        // 操作按钮
        IconButton(
          onPressed: () {},
          icon: const Icon(Icons.more_vert),
        ),
      ],
    ),
  ),
)

示例2:底部导航布局

Scaffold(
  body: const Center(child: Text('内容区域')),
  bottomNavigationBar: BottomNavigationBar(
    currentIndex: 0,
    items: const [
      BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
      BottomNavigationBarItem(icon: Icon(Icons.search), label: '发现'),
      BottomNavigationBarItem(icon: Icon(Icons.person), label: '我的'),
    ],
  ),
)

📝 小结

这一章我们学习了:

  • ✅ Row - 水平布局
  • ✅ Column - 垂直布局
  • ✅ Stack - 层叠布局
  • ✅ Expanded/Flexible - 弹性布局
  • ✅ ListView - 可滚动列表
  • ✅ GridView - 网格布局
  • ✅ Wrap - 自动换行布局
  • ✅ 单子布局:Center、Padding、SizedBox、AspectRatio

布局口诀

  • 横着排用 Row
  • 竖着排用 Column
  • 要重叠用 Stack
  • 要滚动用 ListView
  • 要网格用 GridView
  • 要换行用 Wrap

💪 练习题

  1. 使用 Row 和 Column 创建一个九宫格布局
  2. 使用 ListView.builder 创建一个消息列表(显示头像、昵称、最后一条消息)
  3. 使用 Stack 创建一个带角标的图片(如未读消息数量)
点击查看答案

练习1:九宫格

Column(
  children: [
    Row(
      children: [
        Expanded(child: Container(height: 100, color: Colors.red)),
        Expanded(child: Container(height: 100, color: Colors.green)),
        Expanded(child: Container(height: 100, color: Colors.blue)),
      ],
    ),
    Row(
      children: [
        Expanded(child: Container(height: 100, color: Colors.yellow)),
        Expanded(child: Container(height: 100, color: Colors.purple)),
        Expanded(child: Container(height: 100, color: Colors.orange)),
      ],
    ),
    Row(
      children: [
        Expanded(child: Container(height: 100, color: Colors.cyan)),
        Expanded(child: Container(height: 100, color: Colors.pink)),
        Expanded(child: Container(height: 100, color: Colors.teal)),
      ],
    ),
  ],
)

练习3:带角标的图片

Stack(
  children: [
    Container(
      width: 60,
      height: 60,
      decoration: BoxDecoration(
        color: Colors.grey[300],
        borderRadius: BorderRadius.circular(8),
      ),
      child: const Icon(Icons.message, size: 30),
    ),
    Positioned(
      top: -5,
      right: -5,
      child: Container(
        padding: const EdgeInsets.all(4),
        decoration: const BoxDecoration(
          color: Colors.red,
          shape: BoxShape.circle,
        ),
        child: const Text(
          '3',
          style: TextStyle(color: Colors.white, fontSize: 12),
        ),
      ),
    ),
  ],
)

🚀 下一步

布局系统掌握后,下一章我们来学习 状态管理入门,让应用动起来!


由 编程指南 提供

最近更新: 2026/2/3 16:24
Contributors: 王长安
Prev
第5章 - Widget 基础
Next
第7章 - 状态管理入门