布局概览与基础容器
Flutter 的布局系统基于父约束子模型:父组件告诉子组件「你有多少空间」,子组件决定「我用多少空间」。理解这个模型,是掌握 Flutter 布局的关键。
布局核心原理
约束模型
Flutter 布局过程分两步:
- 向下传递约束:父组件给子组件一组约束(最小/最大宽度、最小/最大高度)
- 向上报告尺寸:子组件在约束范围内决定自己的尺寸,报告给父组件
父组件:"你的宽度必须在 100~300 之间,高度必须在 50~600 之间"
子组件:"好的,我选择 200×100"
父组件:"收到,你在 (x, y) 位置"常见布局组件分类
| 类别 | 组件 | 作用 |
|---|---|---|
| 单子组件 | Container、Padding、Center、Align、SizedBox | 包裹一个子组件,添加装饰/间距/对齐 |
| 多子组件 | Column、Row、Stack、Wrap | 排列多个子组件 |
| 滚动组件 | ListView、GridView、SingleChildScrollView | 内容超出屏幕时可滚动 |
Container — 万能容器
Container 是最常用的组件,它本身没有外观,通过组合装饰、内边距、尺寸等属性来构建视觉效果。
常用属性
dart
Container({
Key? key,
AlignmentGeometry? alignment, // 子组件对齐方式
EdgeInsetsGeometry? padding, // 内边距
Color? color, // 背景色
Decoration? decoration, // 装饰(边框、圆角、渐变等)
Decoration? foregroundDecoration, // 前景装饰
double? width, // 宽度
double? height, // 高度
BoxConstraints? constraints, // 约束
EdgeInsetsGeometry? margin, // 外边距
Matrix4? transform, // 变换
Widget? child, // 子组件
Clip clipBehavior = Clip.none, // 裁剪方式
})基本用法
dart
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: ContainerExamples()));
}
class ContainerExamples extends StatelessWidget {
const ContainerExamples({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Container 示例')),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
// 带背景色和内边距
// ─── ★ Container 基本用法 ──────────────
Container(
color: Colors.blue,
padding: const EdgeInsets.all(16),
child: const Text('Hello', style: TextStyle(color: Colors.white)),
),
// ─── ☆ Container 基本用法 ──────────────
const SizedBox(height: 16),
// 带圆角和边框(必须用 decoration,不能同时设 color)
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.grey),
boxShadow: [
BoxShadow(color: Colors.black26, blurRadius: 4, offset: const Offset(0, 2)),
],
),
child: const Text('Card'),
),
const SizedBox(height: 16),
// 固定尺寸
Container(
width: 200,
height: 100,
color: Colors.amber,
child: const Center(child: Text('200×100')),
),
],
),
);
}
}Container 的尺寸规则
| 条件 | 行为 |
|---|---|
有 child,无尺寸约束 | 跟子组件一样大 |
有 child,有尺寸约束 | 使用约束的尺寸 |
无 child,无尺寸约束 | 尽量大(填满父组件) |
无 child,有尺寸约束 | 使用约束的尺寸 |
注意
color 和 decoration 不能同时设置。如果需要圆角、边框、阴影等装饰,统一用 decoration 中的 color。
SizedBox — 固定尺寸
SizedBox 是最简单的尺寸控制组件,用于给子组件指定固定尺寸,或作为间距占位。
基本用法
dart
// 固定尺寸
SizedBox(
width: 100,
height: 100,
child: Container(color: Colors.blue),
)
// 只约束宽度(高度随内容)
SizedBox(width: 200, child: const Text('xxx'))
// 作为间距使用(无 child)
const SizedBox(height: 16) // 垂直间距 16
const SizedBox(width: 8) // 水平间距 8SizedBox 变体
dart
SizedBox.expand() // 尽可能大
SizedBox.shrink() // 尽可能小(0×0)
SizedBox.square(dimension: 50) // 正方形 50×50建议
在 Row / Column 中用 SizedBox 做间距,比 Padding 更直观:
dart
import 'package:flutter/material.dart';
class SpacingExample extends StatelessWidget {
const SpacingExample({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('第一行'),
const SizedBox(height: 16),
const Text('第二行'),
],
),
),
);
}
}Padding — 内边距
Padding 专门用于给子组件添加内边距。
基本用法
dart
import 'package:flutter/material.dart';
class PaddingExamples extends StatelessWidget {
const PaddingExamples({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
padding: const EdgeInsets.all(16),
children: [
// 四周 16
Padding(
padding: const EdgeInsets.all(16),
child: Container(color: Colors.blue[100], child: const Text('all(16)')),
),
const SizedBox(height: 8),
// 水平16,垂直8
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Container(color: Colors.green[100], child: const Text('symmetric')),
),
const SizedBox(height: 8),
// 只设左边和上边
Padding(
padding: const EdgeInsets.only(left: 16, top: 8),
child: Container(color: Colors.orange[100], child: const Text('only')),
),
const SizedBox(height: 8),
// 左上右下
Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 8),
child: Container(color: Colors.purple[100], child: const Text('fromLTRB')),
),
],
),
);
}
}EdgeInsets 常用构造函数
| 构造函数 | 说明 | 示例 |
|---|---|---|
EdgeInsets.all(n) | 四周相同 | all(16) → 上下左右 16 |
EdgeInsets.symmetric(h, v) | 水平/垂直对称 | symmetric(horizontal: 16, vertical: 8) |
EdgeInsets.only(l, t, r, b) | 只设指定边 | only(left: 16) |
EdgeInsets.fromLTRB(l, t, r, b) | 左上右下分别设置 | fromLTRB(16, 8, 16, 8) |
Padding vs Container 的 padding
dart
import 'package:flutter/material.dart';
class PaddingVsContainer extends StatelessWidget {
const PaddingVsContainer({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// 方式一:Padding 组件(推荐,语义清晰)
Padding(
padding: const EdgeInsets.all(16),
child: Container(color: Colors.blue[100], child: const Text('Padding')),
),
// 方式二:Container 的 padding
Container(
padding: const EdgeInsets.all(16),
color: Colors.green[100],
child: const Text('Container'),
),
],
),
);
}
}建议
如果只需要添加内边距,用 Padding 而非 Container——语义更明确,性能更好。
布局调试技巧
查看布局边界
在 MaterialApp 中开启调试模式:
dart
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(
debugShowCheckedModeBanner: false,
showPerformanceOverlay: false,
home: Scaffold(body: Center(child: Text('调试布局'))),
));
// 在代码中随时调用:
// debugPaintSizeEnabled = true; // 显示布局边界
}使用 Flutter Inspector
在 VS Code / Android Studio 中使用 Flutter Inspector 可视化查看 Widget 树和布局约束。
常见布局问题
| 问题 | 原因 | 解决 |
|---|---|---|
| 组件不显示 | 未设置尺寸或颜色 | 添加 color 或 width/height 调试 |
| 溢出黄条 | 内容超出父组件 | 用 Expanded 包裹或使用 ListView |
| 布局不对齐 | 未设置对齐方式 | 使用 Align / Center |
| 列表只显示一项 | 未给列表指定高度 | 用 Expanded 包裹或给 shrinkWrap: true |
