在 Flutter 中,布局是构建界面的核心。无论多么复杂的界面,都是由基础布局组件组合而成。本节课我们将详细讲解 Flutter 中最常用的布局组件,包括线性布局(Row/Column)、层叠布局(Stack)以及辅助布局组件,帮助你掌握界面搭建的基础能力。
一、线性布局:Row 与 Column
线性布局是最常用的布局方式,通过水平方向(Row) 或垂直方向(Column) 排列子组件。
1. Row:水平排列子组件
Row 组件用于在水平方向上排列子组件,它的构造函数简化如下:
Row({
Key? key,
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start, // 主轴对齐方式
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center, // 交叉轴对齐方式
MainAxisSize mainAxisSize = MainAxisSize.max, // 主轴尺寸(占满父组件还是包裹子组件)
VerticalDirection verticalDirection = VerticalDirection.down, // 垂直方向排序
TextDirection? textDirection, // 水平方向排序(影响 start/end 的判断)
List<Widget> children = const [], // 子组件列表
})
示例代码:
Row(
children: [
Container(width: 50, height: 50, color: Colors.red),
Container(width: 60, height: 60, color: Colors.green),
Container(width: 70, height: 70, color: Colors.blue),
],
)
运行后会看到三个颜色块在水平方向依次排列。
2. Column:垂直排列子组件
Column 与 Row 用法完全一致,唯一区别是垂直方向排列子组件:
Column(
children: [
Container(width: 50, height: 50, color: Colors.red),
Container(width: 60, height: 60, color: Colors.green),
Container(width: 70, height: 70, color: Colors.blue),
],
)
3. 主轴与交叉轴
理解主轴和交叉轴是掌握线性布局的关键:
-
主轴:组件排列的方向
Row的主轴是水平方向(左右)Column的主轴是垂直方向(上下)
-
交叉轴:与主轴垂直的方向
Row的交叉轴是垂直方向(上下)Column的交叉轴是水平方向(左右)
二、对齐方式:MainAxisAlignment 与 CrossAxisAlignment
通过对齐方式可以精确控制子组件在主轴和交叉轴上的位置。
1. 主轴对齐(MainAxisAlignment)
控制子组件在主轴上的排列方式,常用值包括:
start:沿主轴起点对齐(Row 左对齐,Column 上对齐)end:沿主轴终点对齐(Row 右对齐,Column 下对齐)center:主轴居中对齐spaceBetween:子组件之间平均分配空间(两端组件顶边)spaceAround:子组件两侧均匀分配空间(两端空间是中间的一半)spaceEvenly:所有空间(包括两端)平均分配
示例(Row + spaceBetween) :
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
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),
],
)
2. 交叉轴对齐(CrossAxisAlignment)
控制子组件在交叉轴上的排列方式,常用值包括:
start:沿交叉轴起点对齐end:沿交叉轴终点对齐center:交叉轴居中对齐(默认值)stretch:子组件拉伸至填满交叉轴(需子组件无固定尺寸)baseline:按基线对齐(仅 Row 有效,与文字基线相关)
示例(Row + stretch) :
Row(
crossAxisAlignment: CrossAxisAlignment.stretch, // 垂直方向拉伸
children: [
Container(width: 50, color: Colors.red), // 不指定高度,会被拉伸
Container(width: 50, height: 60, color: Colors.green),
Container(width: 50, height: 70, color: Colors.blue),
],
)
三、层叠布局:Stack 与 Positioned
当需要子组件堆叠显示(如图片上叠加文字)时,使用 Stack 与 Positioned 组合。
1. Stack:堆叠子组件
Stack 会将子组件按顺序堆叠(后添加的组件在上方),构造函数简化如下:
Stack({
Key? key,
AlignmentGeometry alignment = Alignment.center, // 未定位子组件的对齐方式
TextDirection? textDirection,
StackFit fit = StackFit.loose, // 子组件尺寸适配方式
Clip clipBehavior = Clip.hardEdge, // 超出范围是否裁剪
List<Widget> children = const [],
})
基础示例:
Stack(
children: [
// 底层红色容器
Container(width: 200, height: 200, color: Colors.red),
// 中间绿色容器(叠在红色上)
Container(width: 150, height: 150, color: Colors.green),
// 顶层蓝色容器(叠在最上面)
Container(width: 100, height: 100, color: Colors.blue),
],
)
2. Positioned:定位子组件
Positioned 用于在 Stack 中精确定位子组件,必须作为 Stack 的直接子组件使用,常用属性:
left:距离 Stack 左边缘的距离right:距离 Stack 右边缘的距离top:距离 Stack 上边缘的距离bottom:距离 Stack 下边缘的距离width/height:指定子组件的宽高(可选)
示例:
Stack(
children: [
Container(width: 200, height: 200, color: Colors.grey),
// 左上角定位
Positioned(
left: 10,
top: 10,
child: Container(width: 50, height: 50, color: Colors.red),
),
// 右下角定位
Positioned(
right: 10,
bottom: 10,
child: Container(width: 50, height: 50, color: Colors.blue),
),
],
)
四、常用布局辅助 Widget
这些组件本身不负责布局,但能辅助调整子组件的位置、尺寸等。
1. Padding:内边距
为子组件添加内边距(子组件与父容器边缘的距离):
Padding(
padding: EdgeInsets.all(16), // 四个方向都添加16px内边距
// 也可以单独设置:EdgeInsets.only(left: 10, top: 20)
child: Container(width: 100, height: 100, color: Colors.red),
)
EdgeInsets 常用构造:
all(value):四边统一值only(left, top, right, bottom):单独设置symmetric(horizontal, vertical):水平 / 垂直对称设置
2. Margin:外边距
Flutter 中没有单独的 Margin 组件,通过 Container 的 margin 属性实现(子组件与其他组件的距离):
Container(
margin: EdgeInsets.all(10), // 外边距
padding: EdgeInsets.all(10), // 内边距
color: Colors.grey,
child: Container(width: 50, height: 50, color: Colors.red),
)
3. Center:居中对齐
简化版的对齐组件,等价于 Align(alignment: Alignment.center, child: ...):
Center(
child: Container(width: 100, height: 100, color: Colors.green),
)
4. Expanded:占满剩余空间
在 Row 或 Column 中,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),
],
)
Row(
children: [
Expanded(
flex: 1, // 占1份
child: Container(height: 50, color: Colors.red),
),
Expanded(
flex: 2, // 占2份(总空间分为3份)
child: Container(height: 50, color: Colors.green),
),
],
)
五、综合示例:组合布局
实际开发中,布局组件通常需要嵌套使用。以下是一个简单的用户信息卡片示例:
Container(
width: 300,
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
boxShadow: [BoxShadow(color: Colors.grey, blurRadius: 3)],
),
child: Row(
// 水平排列头像和信息
children: [
// 头像
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(30),
),
),
SizedBox(width: 12), // 间距
// 信息区域(垂直排列)
Expanded(
// 占满剩余宽度
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, // 左对齐
children: [
Text(
"张三",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 4),
Text("Flutter 开发者", style: TextStyle(color: Colors.grey)),
],
),
),
// 右侧箭头
Icon(Icons.arrow_right, color: Colors.grey),
],
),
)