Flutter 入门第二课:核心布局组件(Container Row Column)
这节课是 Flutter页面排版的核心,学会Container(容器)、Row(行)、Column(列)三个组件,就能像搭积木一样拼出任意静态页面的骨架(比如个人中心、商品卡片、登录页排版),也是后续所有复杂布局的基础。
课前回顾
- Flutter 页面固定结构:
MaterialApp → Scaffold → body,所有布局 / UI 都写在body里; - 一切皆 Widget,布局的本质是Widget 的嵌套(父组件包孩子组件,孩子可以是单个 / 多个);
- 后续代码都基于无状态组件(StatelessWidget),直接替换
lib/main.dart即可,热重载看效果。
一、最核心的容器:Container
Container是 Flutter 中最常用的布局容器,相当于「一个带样式的盒子」,可以包裹任意子 Widget,给它设置宽高、背景、边距、内边距、圆角、阴影等样式,还能做简单的定位。
核心作用
- 给子 Widget 设置统一的样式(比如给 Text 加背景、给 Image 加圆角);
- 作为布局的「基础单元」,配合 Row/Column 实现复杂排版;
- 单独使用时,可作为页面的分区容器(比如把页面分成顶部 / 中间 / 底部)。
核心属性(必记,高频使用)
表格
| 属性 | 作用 | 常用值 / 类型 |
|---|---|---|
width/height |
容器宽高 | 数字(如 200、100) |
color |
背景颜色 | Colors.xxx(如 Colors.white) |
margin |
容器外部的间距(和其他组件的距离) | EdgeInsets.all (10)(全方向 10)、EdgeInsets.only (left:10)(仅左 10) |
padding |
容器内部的间距(和子 Widget 的距离) | 和 margin 用法完全一致 |
decoration |
复杂装饰(渐变 / 圆角 / 阴影,不能和 color 同时用) | BoxDecoration () 包裹 |
alignment |
子 Widget 在容器内的对齐方式 | Alignment.xxx(如居中 Alignment.center) |
实战代码:Container 的基础用法
直接替换main.dart,注释写满了,热重载看效果:
dart
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Container布局',
theme: ThemeData(primarySwatch: Colors.blue),
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Container核心用法")),
// 页面背景色(避免白色太单调)
backgroundColor: Colors.grey[100],
body: Center(
child: Container(
// 1. 宽高
width: 300,
height: 200,
// 2. 外部间距:和屏幕四周的距离
margin: EdgeInsets.all(20),
// 3. 内部间距:和子组件Text的距离
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 30), // 水平20,垂直30
// 4. 复杂装饰:圆角+阴影+背景(替代color)
decoration: BoxDecoration(
color: Colors.white, // 背景色
borderRadius: BorderRadius.circular(16), // 圆角16(数字越大越圆)
boxShadow: [ // 阴影:数组形式,可加多个阴影
BoxShadow(
color: Colors.grey[300]!, // 阴影颜色(!表示非空,空安全要求)
blurRadius: 10, // 模糊程度(数字越大越模糊)
spreadRadius: 2, // 扩散程度
offset: Offset(0, 3), // 偏移:(x,y) 右正下正
)
]
),
// 5. 子组件在容器内的对齐:居中
alignment: Alignment.center,
// 子Widget:一个Text
child: Text(
"Container盒子",
style: TextStyle(fontSize: 20, color: Colors.blue),
),
),
),
);
}
}
运行效果
屏幕中间出现一个白色圆角盒子,带浅灰色阴影,内部文字居中,盒子和屏幕、文字和盒子都有指定间距,这是日常开发中最常见的卡片样式(比如商品卡片、消息卡片)。
关键注意点
- color 和 decoration 互斥:想加圆角 / 阴影时,必须把背景色写在
BoxDecoration里,不能单独写color,否则会报错; - margin 和 padding 的区别:记一句话「margin 管外,padding 管内」,新手别搞混;
- 宽高可选:如果 Container 放在 Row/Column 里,宽高可能会被布局约束覆盖(后续讲),单独使用时建议指定。
二、线性布局:Row(行)和 Column(列)
Row和Column是 Flutter 的基础线性布局,专门实现横向 / 纵向的多组件排列,比如:
- Row:导航栏的「图标 + 文字」、商品卡片的「图片 + 价格 + 按钮」(横向排);
- Column:登录页的「账号输入框 + 密码输入框 + 登录按钮」、个人中心的「头像 + 昵称 + 手机号」(纵向排)。
核心共性
- 都是多子组件布局:孩子用
children(数组)包裹,可放任意多个 Widget(区别于 Container 的child单孩子); - 都有主轴和副轴:布局的核心是「主轴对齐」和「副轴对齐」,这是掌握 Row/Column 的关键;
- 都支持弹性布局(Expanded):解决「子组件占满剩余空间」的适配问题(后续重点讲)。
先搞懂:主轴和副轴(必记,不搞混)
这是 Row/Column 的核心概念,一句话讲清:
- 主轴:组件排列的方向(Row 是横向,Column 是纵向);
- 副轴:和主轴垂直的方向(Row 是纵向,Column 是横向)。
表格
| 布局 | 主轴方向 | 副轴方向 | 核心对齐属性(主轴) | 核心对齐属性(副轴) |
|---|---|---|---|---|
| Row | 横向(左右) | 纵向(上下) | mainAxisAlignment |
crossAxisAlignment |
| Column | 纵向(上下) | 横向(左右) | mainAxisAlignment |
crossAxisAlignment |
1. Row(行:横向排列)
核心属性(高频)
children:数组,放需要横向排列的子 Widget(必填);mainAxisAlignment:主轴(左右)对齐,控制子组件在水平方向的位置;crossAxisAlignment:副轴(上下)对齐,控制子组件在垂直方向的位置;margin/padding:和 Container 用法一致,给 Row 整体加外 / 内边距;mainAxisSize:主轴占用空间(MainAxisSize.max占满整行,min自适应子组件宽度,默认 max)。
主轴对齐(mainAxisAlignment)常用值
MainAxisAlignment.start:左对齐(默认);MainAxisAlignment.center:水平居中;MainAxisAlignment.end:右对齐;MainAxisAlignment.spaceBetween:两端对齐(子组件之间间距相等,无左右边距);MainAxisAlignment.spaceAround:所有子组件两侧间距相等(左右有一半间距);MainAxisAlignment.spaceEvenly:所有间距(子组件之间 + 左右)完全相等。
实战代码:Row 的横向排列 + 对齐
dart
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Row布局',
theme: ThemeData(primarySwatch: Colors.blue),
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Row行布局")),
body: Container(
width: double.infinity, // 占满整行宽度
height: 100,
color: Colors.grey[100],
margin: EdgeInsets.all(20),
child: Row(
// 主轴(左右):两端对齐
mainAxisAlignment: MainAxisAlignment.spaceBetween,
// 副轴(上下):垂直居中
crossAxisAlignment: CrossAxisAlignment.center,
// 横向排列的3个子Widget(Container+Text+Icon)
children: [
// 子1:红色小盒子
Container(width: 50, height: 50, color: Colors.red),
// 子2:文字
Text("Row横向排列", style: TextStyle(fontSize: 18)),
// 子3:图标
Icon(Icons.arrow_forward_ios, color: Colors.blue, size: 20),
],
),
),
);
}
}
运行效果
一个灰色长条容器内,红色小盒子居左、文字居中、图标居右,三者垂直居中对齐,这是列表项的经典排版(比如消息列表、商品列表的左侧图标 + 中间文字 + 右侧箭头)。
2. Column(列:纵向排列)
核心属性(和 Row 完全一致,只是主轴 / 副轴方向变了)
children:数组,放需要纵向排列的子 Widget(必填);mainAxisAlignment:主轴(上下)对齐,控制子组件在垂直方向的位置;crossAxisAlignment:副轴(左右)对齐,控制子组件在水平方向的位置;- 其他属性(margin/padding/mainAxisSize)和 Row 完全一样。
主轴对齐(mainAxisAlignment)常用值
和 Row 一致,只是方向变成上下:start(上对齐,默认)、center(垂直居中)、end(下对齐)、spaceBetween(上下两端对齐)等。
实战代码:Column 的纵向排列 + 对齐
模拟个人中心的头像 + 昵称 + 手机号排版,经典纵向布局:
dart
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Column布局',
theme: ThemeData(primarySwatch: Colors.blue),
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Column列布局")),
body: Center(
child: Container(
width: 200,
height: 250,
color: Colors.white,
margin: EdgeInsets.all(20),
padding: EdgeInsets.all(30),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
boxShadow: [BoxShadow(color: Colors.grey[300]!, blurRadius: 8)],
),
child: Column(
// 主轴(上下):垂直居中
mainAxisAlignment: MainAxisAlignment.center,
// 副轴(左右):水平居中
crossAxisAlignment: CrossAxisAlignment.center,
// 纵向排列的3个子Widget
children: [
// 子1:圆形头像(Container做圆形)
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Colors.blue[100],
borderRadius: BorderRadius.circular(40), // 宽高的一半=圆形
),
alignment: Alignment.center,
child: Icon(Icons.person, color: Colors.blue, size: 40),
),
// 子组件之间的间距:SizedBox(空白盒子,专门用来占位)
SizedBox(height: 15),
// 子2:昵称文字
Text("Flutter学习者", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
// 子组件之间的间距
SizedBox(height: 8),
// 子3:手机号文字
Text("13800138000", style: TextStyle(fontSize: 14, color: Colors.grey[600])),
],
),
),
),
);
}
}
运行效果
一个白色圆角卡片,内部圆形头像在上、昵称在中、手机号在下,三者全部水平居中,子组件之间有指定间距,这是个人中心 / 用户卡片的经典排版。
小技巧:SizedBox(空白占位符)
Flutter 中没有「间距属性」,想给 Row/Column 的子组件之间加间距,用SizedBox:
- 横向间距:
SizedBox(width: 10)(Row 中用); - 纵向间距:
SizedBox(height: 10)(Column 中用); - 作用:纯空白的盒子,只占指定宽 / 高,无样式,专门用来做组件间的间距,比 margin 更灵活。
三、Row+Column+Container 嵌套实战(核心重点)
实际开发中,没有单独使用 Row/Column 的场景,都是三者嵌套实现复杂排版 —— 比如「横向排的行里,嵌套纵向排的列;列里又嵌套带样式的容器」。
实战需求:实现一个商品卡片(电商 APP 最常见的布局)
需求拆解
- 整体是一个圆角卡片(Container),占满屏幕宽度,有固定高度、阴影;
- 卡片内部横向排列(Row):左侧商品图片 + 右侧信息区域;
- 右侧信息区域纵向排列(Column):商品名称(上)+ 商品描述(中)+ 价格 + 销量(下,又一个 Row);
- 所有元素对齐合理,有指定间距。
完整代码(直接复制运行,注释超详细)
dart
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '商品卡片布局',
theme: ThemeData(primarySwatch: Colors.blue),
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("三者嵌套实战-商品卡片")),
backgroundColor: Colors.grey[100],
body: Container(
// 整体卡片的外间距
margin: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Container(
// 商品卡片主容器:圆角+阴影+背景
width: double.infinity,
height: 120,
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [BoxShadow(color: Colors.grey[200]!, blurRadius: 5)],
),
// 卡片内部:横向排列(图片+信息)
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// 左侧:商品图片容器
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(8),
// 网络图片:fit=BoxFit.cover 填充容器,不变形
image: DecorationImage(
image: NetworkImage("https://picsum.photos/200/200"), // 测试图片
fit: BoxFit.cover,
),
),
),
// 图片和右侧信息的横向间距
SizedBox(width: 15),
// 右侧:信息区域(纵向排列)
Expanded( // 关键:占满剩余水平空间(适配屏幕)
child: Column(
// 主轴(上下):顶部对齐,因为信息高度不够
mainAxisAlignment: MainAxisAlignment.start,
// 副轴(左右):左对齐
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 商品名称
Text(
"Flutter零基础入门教程 全套视频",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
maxLines: 1, // 只显示1行
overflow: TextOverflow.ellipsis, // 超出部分显示...
),
// 间距
SizedBox(height: 8),
// 商品描述
Text(
"从环境搭建到项目实战,一步一步教你学Flutter",
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
maxLines: 2, // 最多显示2行
overflow: TextOverflow.ellipsis,
),
// 间距
SizedBox(height: 10),
// 价格+销量(横向排列,嵌套Row)
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// 价格
Text(
"¥99.00",
style: TextStyle(fontSize: 14, color: Colors.red, fontWeight: FontWeight.bold),
),
// 销量
Text(
"已售1000+",
style: TextStyle(fontSize: 12, color: Colors.grey[500]),
),
],
),
],
),
),
],
),
),
),
);
}
}
运行效果
一个标准的电商商品卡片,左侧方形图片、右侧文字信息,文字区域内名称单行省略、描述两行省略,底部价格居左、销量居右,适配所有屏幕宽度,是企业开发中直接能用的布局模板。
核心知识点:Expanded(弹性扩展)
这是本次实战的关键,解决了 Flutter 布局的适配问题:
- 作用:只能用在Row/Column的子组件中,让子组件占满主轴方向的剩余空间;
- 场景:比如本次实战中,右侧信息区域在 Row 里,加了
Expanded后,会自动占满「屏幕宽度 - 图片宽度 - 间距」的剩余空间,适配所有手机; - 注意:Row 里的 Expanded 占剩余水平空间,Column 里的占剩余垂直空间;
- 多个 Expanded 可按比例分配空间(加
flex: 1属性,比如 flex:1 和 flex:2,就是 1:2 分配)。
Text 的溢出处理(实战必备)
开发中文字经常会超出容器,必须加溢出处理,否则会报错:
maxLines: n:最多显示 n 行;overflow: TextOverflow.ellipsis:超出部分显示...;- 两者必须配合使用,缺一不可。
四、本节课核心总结(必背)
-
Container:带样式的「盒子」,核心管宽高、边距、内边距、样式,包裹单个 Widget;
-
Row/Column:线性布局,核心管横向 / 纵向排列,孩子用
children(数组),重点区分主轴 / 副轴对齐; -
嵌套原则:Row 里可以嵌套 Column,Column 里可以嵌套 Row,所有组件都可以被 Container 包裹加样式;
-
三个实用小部件:
SizedBox:组件间的间距占位符;Expanded:Row/Column 子组件的弹性扩展,解决适配问题;Text溢出:maxLines + overflow,实战必加;
-
布局的本质:Widget 的嵌套,遵循「从外到内、从大到小」的思路(先搭大框架,再填小细节)。
五、课后练习(敲代码才是硬道理)
看完不如敲一遍,推荐 3 个练习,从简单到复杂,巩固本节课知识点:
练习 1:简单版
实现「导航栏布局」:Row 包裹「左侧文字(返回)+ 中间文字(页面标题)+ 右侧图标(设置)」,三者分别居左、居中、居右,垂直居中对齐。
练习 2:进阶版
实现「登录页布局」:Column 包裹「两个 TextField 输入框(账号 / 密码)+ 一个登录按钮」,所有组件水平居中,组件间有间距,整体在屏幕垂直居中。
练习 3:实战版
修改本节课的商品卡片代码,添加「右侧收藏图标」(在 Row 的最右侧,和图片、信息区域横向排列),实现「图片 + 信息 + 收藏图标」的三栏布局。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)