← Frontend / Flutter

03_布局系统

Flutter 布局系统和常用布局组件

Flutter 的布局核心是 Row(水平)和 Column(垂直),对应 CSS Flexbox。没有独立 CSS 文件,样式完全通过 Widget 属性描述。


Row / Column 对应 CSS Flexbox

CSS Flexbox Flutter
display: flex; flex-direction: row Row
display: flex; flex-direction: column Column
justify-content mainAxisAlignment
align-items crossAxisAlignment
flex: 1 Expanded(flex: 1)
gap: 16px 子项间插入 SizedBox(width/height: 16)
Row(
  mainAxisAlignment: MainAxisAlignment.spaceBetween, // justify-content
  crossAxisAlignment: CrossAxisAlignment.center,      // align-items
  children: [
    Text('左'),
    Text('中'),
    Text('右'),
  ],
)

Column(
  mainAxisAlignment: MainAxisAlignment.center,
  crossAxisAlignment: CrossAxisAlignment.stretch, // 子元素撑满宽度
  children: [
    Text('第一行'),
    const SizedBox(height: 12),  // 行间距(类似 gap 或 margin-bottom)
    Text('第二行'),
    const SizedBox(height: 12),
    Text('第三行'),
  ],
)

mainAxisAlignment 速查(对应 justify-content):

Flutter CSS
start flex-start
center center
end flex-end
spaceBetween space-between
spaceEvenly space-evenly
spaceAround space-around

Expanded 和 Flexible(对应 flex)

Row(
  children: [
    // Expanded:占满剩余空间(类似 flex: 1)
    Expanded(
      flex: 2,                 // 占 2/3
      child: Container(color: Colors.blue, height: 50),
    ),
    Expanded(
      flex: 1,                 // 占 1/3
      child: Container(color: Colors.red, height: 50),
    ),
  ],
)

// Flexible:最多占指定比例,内容不足时可缩小(类似 flex-shrink)
Row(
  children: [
    Flexible(child: Text('可被压缩的长文字内容...')),
    const Icon(Icons.info),
  ],
)

Stack(对应 position: absolute)

// Stack = CSS position: relative 的父容器
// Positioned = CSS position: absolute 的子元素
Stack(
  children: [
    // 底层:背景图
    Image.network(
      'https://example.com/bg.jpg',
      width: double.infinity,
      height: 200,
      fit: BoxFit.cover,
    ),

    // 渐变遮罩层
    Container(
      height: 200,
      decoration: const BoxDecoration(
        gradient: LinearGradient(
          begin: Alignment.topCenter,
          end: Alignment.bottomCenter,
          colors: [Colors.transparent, Colors.black54],
        ),
      ),
    ),

    // 定位文字(类似 position: absolute; bottom: 16; left: 16)
    const Positioned(
      bottom: 16,
      left: 16,
      child: Text(
        '图片标题',
        style: TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold),
      ),
    ),
  ],
)

SizedBox 和 Spacer

// SizedBox:固定尺寸空白,常用于间距
SizedBox(width: 16)           // 水平间距(Row 中用)
SizedBox(height: 12)          // 垂直间距(Column 中用)
SizedBox(width: 200, height: 100, child: someWidget) // 固定尺寸容器

// Spacer:弹性填充剩余空间(类似 flex: 1 的空白块)
Row(
  children: [
    Text('左侧内容'),
    const Spacer(),            // 撑开中间空白
    Text('右侧内容'),          // 自然右对齐
  ],
)

Padding 和 Center

// Padding:仅添加内边距(比 Container 更轻量)
Padding(
  padding: const EdgeInsets.all(16),
  child: Text('内容'),
)

// Center:居中子元素(类似 CSS flex + justify/align center)
Center(child: Text('居中'))

// Align:指定对齐
Align(
  alignment: Alignment.bottomRight,
  child: Text('右下角'),
)

// EdgeInsets 速查
EdgeInsets.all(16)                        // 四边均为 16
EdgeInsets.symmetric(horizontal: 20, vertical: 10) // 左右 20,上下 10
EdgeInsets.only(top: 8, left: 16)         // 指定方向
EdgeInsets.fromLTRB(16, 8, 16, 8)        // 完全自定义

Wrap(自动换行,类似 flex-wrap)

// 类比 CSS flex-wrap: wrap
Wrap(
  spacing: 8,                  // 主轴间距(类似 column-gap)
  runSpacing: 8,               // 交叉轴间距(类似 row-gap)
  children: ['Flutter', 'Dart', 'Mobile', 'iOS', 'Android'].map((tag) =>
    Chip(
      label: Text(tag),
      backgroundColor: Colors.blue.shade100,
    ),
  ).toList(),
)

ConstrainedBox / FractionallySizedBox(尺寸约束)

// ConstrainedBox:限制子 Widget 的最小/最大尺寸(类似 min-width / max-width)
ConstrainedBox(
  constraints: const BoxConstraints(
    minWidth: 100,
    maxWidth: 300,
    minHeight: 48,
  ),
  child: ElevatedButton(onPressed: () {}, child: const Text('按钮')),
)

// FractionallySizedBox:按父容器百分比设置尺寸(类似 width: 80%)
FractionallySizedBox(
  widthFactor: 0.8,            // 占父容器宽度的 80%
  child: ElevatedButton(onPressed: () {}, child: const Text('80% 宽按钮')),
)

// SizedBox.expand():占满父容器(类似 width: 100%; height: 100%)
SizedBox.expand(
  child: Container(color: Colors.blue),
)

// width: double.infinity = width: 100%(最常用写法)
Container(
  width: double.infinity,
  child: ElevatedButton(onPressed: () {}, child: const Text('全宽按钮')),
)