第4章:布局与样式系统
Flutter 中一切皆是 Widget,而布局的核心在于理解“盒模型”和“约束系统”。掌握这些,可以构建出结构清晰、样式统一、适配良好的界面。
一、Flutter 的盒模型与布局约束机制
🔹 Flutter 的布局规则:
- 父组件向子组件 传递约束(constraints);
- 子组件在这些约束内 决定自己的尺寸;
- 子组件将尺寸反馈给父组件,父组件据此决定布局。
例如:Container(width: 100, height: 50) 会给子组件固定宽高的约束。
🔹 Flutter 中的盒模型:
类似前端 CSS,Flutter 的组件结构也具备:
- Padding(内边距)
- Margin(外边距)
- Alignment(对齐方式)
- Constraints(尺寸约束)
二、常用布局控制组件
1. Padding & Margin(内外边距)
Padding(
padding: EdgeInsets.all(16.0),
child: Text("Inside padding"),
)
Margin 不存在单独组件,可通过 Container 实现:
Container(
margin: EdgeInsets.only(top: 20),
child: Text("With margin"),
)
2. Align(对齐方式)
Align(
alignment: Alignment.centerRight,
child: Text("Aligned Text"),
)
常见对齐位置有:topLeft、center、bottomRight 等。
3. Expanded(自适应空间填充)
Row(
children: [
Expanded(child: Container(color: Colors.blue, height: 50)),
Container(width: 50, color: Colors.red),
],
)
Expanded 用于在 Row 或 Column 中按比例占满空间。
三、自定义样式与主题(Theme)
使用全局 Theme 控制字体、颜色、按钮等样式统一风格。
示例:配置全局主题
MaterialApp(
theme: ThemeData(
primarySwatch: Colors.teal,
textTheme: TextTheme(
bodyMedium: TextStyle(fontSize: 16),
),
),
home: MyHomePage(),
)
获取当前主题样式
Text(
"Title",
style: Theme.of(context).textTheme.titleLarge,
)
四、响应式设计:MediaQuery & LayoutBuilder
1. MediaQuery(设备信息)
double screenWidth = MediaQuery.of(context).size.width;
可获取屏幕宽高、系统字体缩放、设备方向等。
2. LayoutBuilder(根据布局环境动态构建)
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return Text("手机布局");
} else {
return Text("平板/桌面布局");
}
},
)
用于实现响应式布局切换,常用于平板或 Web 端适配。
五、常见问题解析
❗ 问题 1:布局不生效的原因
常见症状:
- Container 无显示
- 设置宽高无效
- 对齐方式不起作用
常见原因:
- 子组件尺寸未明确,未受到有效约束
- 忘记设置
Expanded、Flexible - 忘记指定父布局(如 Row/Column/Stack)
示例:
// 错误示例:Text 不换行溢出
Container(
width: 100,
child: Text('这是一段非常长的文字内容这是一段非常长的文字内容'),
)
// 正确:
Container(
width: 100,
child: Text(
'这是一段非常长的文字内容',
softWrap: true,
overflow: TextOverflow.ellipsis,
),
)
❗ 问题 2:Expanded 与 Flexible 的区别
| 特性 | Expanded | Flexible |
|---|---|---|
| 自动占满剩余空间 | ✅ 是 | ❌ 不是(需设置 fit) |
| 控制占比 | ❌ 固定平分(或通过 flex) | ✅ 可以更灵活控制 |
| 常用场景 | 简单平分布局 | 自定义占比、复杂嵌套结构 |
示例:
// Expanded 平分剩余空间
Row(
children: [
Expanded(child: Container(color: Colors.blue)),
Expanded(child: Container(color: Colors.green)),
],
)
// Flexible 可控制是否占满空间
Flexible(
flex: 2,
fit: FlexFit.tight, // 紧凑占满
child: Container(color: Colors.orange),
)