基础入门 Flutter for OpenHarmony:Row 与 Column — 线性布局利器
在 Flutter 的布局体系中,Row和Column是最基础也最常用的两个布局组件,它们都继承自Flex组件,用于实现线性布局。简单来说,Row 将子组件水平排列,Column 将子组件垂直排列。Row 和 Column 是 Flutter 布局的基石,掌握它们的使用对于构建复杂界面至关重要。

🎯欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
📐 本文将带你深入掌握 Flutter 中最基础也是最重要的两个布局组件——Row 和 Column,理解线性布局的精髓。
一、线性布局概述
在 Flutter 的布局体系中,Row 和 Column 是最基础也最常用的两个布局组件,它们都继承自 Flex 组件,用于实现线性布局。简单来说,Row 将子组件水平排列,Column 将子组件垂直排列。
🎯 为什么线性布局如此重要?
线性布局是构建复杂界面的基础,几乎所有的界面都可以拆解为多个线性布局的组合。掌握 Row 和 Column 的使用,就等于掌握了 Flutter 布局的半壁江山。
Row 和 Column 的核心优势:
- 简单直观:布局逻辑清晰,易于理解和维护
- 灵活强大:通过各种属性可以实现丰富的布局效果
- 性能优异:轻量级组件,渲染效率高
- 组合能力强:可以嵌套使用,构建复杂的界面结构
💡 核心思想:Row 和 Column 就像是搭建积木的基础块,通过它们的组合和嵌套,可以构建出任何复杂的界面布局。理解线性布局的工作原理,是掌握 Flutter 布局的关键。
二、Row 水平布局详解
2.1 基础用法
Row 将子组件沿着主轴(水平方向)排列。最简单的使用方式就是将多个子组件放在 children 列表中。
Row(
children: const [
Icon(Icons.star, color: Colors.yellow),
Icon(Icons.star, color: Colors.yellow),
Icon(Icons.star, color: Colors.yellow),
Icon(Icons.star, color: Colors.yellow),
Icon(Icons.star_half, color: Colors.yellow),
],
)
默认情况下,Row 会将子组件紧凑地排列在一起,不会占用多余的横向空间。
2.2 主轴对齐 mainAxisAlignment
mainAxisAlignment 控制子组件在主轴(Row 中是水平方向)上的对齐方式。这是布局中最重要的属性之一。
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text('左边'),
Text('中间'),
Text('右边'),
],
)
MainAxisAlignment 提供了六种对齐方式:
| 值 | 说明 | 视觉效果 |
|---|---|---|
start |
起始对齐 | 所有子组件靠左对齐 |
end |
结束对齐 | 所有子组件靠右对齐 |
center |
居中对齐 | 所有子组件在中间 |
spaceBetween |
两端对齐 | 首尾贴边,中间均匀分布 |
spaceAround |
环绕对齐 | 每个子组件两侧空间相等 |
spaceEvenly |
均匀对齐 | 所有间隔完全相等 |
💡 小贴士:
spaceBetween最适合导航栏等需要首尾贴边的场景;spaceEvenly适合需要完全均匀分布的按钮组。
2.3 交叉轴对齐 crossAxisAlignment
crossAxisAlignment 控制子组件在交叉轴(Row 中是垂直方向)上的对齐方式。
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Icon(Icons.person, size: 40),
Text('用户名'),
],
)
CrossAxisAlignment 提供了五种对齐方式:
| 值 | 说明 | 视觉效果 |
|---|---|---|
start |
起始对齐 | 所有子组件顶部对齐 |
end |
结束对齐 | 所有子组件底部对齐 |
center |
居中对齐 | 所有子组件垂直居中 |
stretch |
拉伸对齐 | 子组件高度拉伸到父组件高度 |
baseline |
基线对齐 | 按文本基线对齐(仅限文本) |
2.4 主轴尺寸 mainAxisSize
mainAxisSize 控制 Row 在主轴方向上的尺寸。
Row(
mainAxisSize: MainAxisSize.min,
children: const [
Text('紧凑布局'),
],
)
| 值 | 说明 | 使用场景 |
|---|---|---|
max |
最大尺寸(默认) | 需要占满父组件宽度 |
min |
最小尺寸 | 需要紧凑布局 |
⚠️ 注意:当
mainAxisSize为max时,Row 会尝试占满父组件的宽度;为min时,Row 的宽度等于子组件的总宽度。
三、Column 垂直布局详解
3.1 基础用法
Column 将子组件沿着主轴(垂直方向)排列,其用法与 Row 非常相似,只是主轴方向不同。
Column(
children: const [
Text('标题', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
Text('副标题', style: TextStyle(fontSize: 16)),
Text('正文内容', style: TextStyle(fontSize: 14)),
],
)
Column 是构建垂直列表、表单、卡片内容等最常用的布局组件。
3.2 主轴对齐 mainAxisAlignment
在 Column 中,mainAxisAlignment 控制子组件在垂直方向上的对齐方式。
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text('顶部'),
Text('中间'),
Text('底部'),
],
)
虽然 MainAxisAlignment 的枚举值与 Row 相同,但在 Column 中的视觉效果完全不同:
| 值 | Row 中的效果 | Column 中的效果 |
|---|---|---|
start |
靠左对齐 | 靠顶对齐 |
end |
靠右对齐 | 靠底对齐 |
center |
水平居中 | 垂直居中 |
spaceBetween |
水平两端对齐 | 垂直两端对齐 |
spaceAround |
水平环绕对齐 | 垂直环绕对齐 |
spaceEvenly |
水平均匀对齐 | 垂直均匀对齐 |
3.3 交叉轴对齐 crossAxisAlignment
在 Column 中,crossAxisAlignment 控制子组件在水平方向上的对齐方式。
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text('左对齐的文本'),
Text('也是左对齐'),
],
)
对于 Column 来说,crossAxisAlignment 通常用于控制文本的对齐方式,或者让多个子组件水平居中对齐。
3.4 垂直方向尺寸
与 Row 类似,Column 的 mainAxisSize 控制垂直方向的尺寸。
Column(
mainAxisSize: MainAxisSize.min,
children: const [
Text('紧凑的垂直布局'),
],
)
💡 小贴士:在可滚动的列表(如 ListView)中,Column 通常使用
mainAxisSize: MainAxisSize.min,以避免不必要的垂直空间占用。
四、Expanded 和 Flexible
4.1 Expanded 填充剩余空间
Expanded 是 Row 和 Column 中最重要的组件之一,它可以让子组件填充父组件的剩余空间。
Row(
children: const [
Text('左侧固定'),
Expanded(
child: Text('中间占据剩余空间', textAlign: TextAlign.center),
),
Text('右侧固定'),
],
)
Expanded 默认会让子组件均匀分配剩余空间,也可以通过 flex 参数控制分配比例。
Row(
children: const [
Expanded(
flex: 1,
child: ColoredBox(color: Colors.red, child: Text('1')),
),
Expanded(
flex: 2,
child: ColoredBox(color: Colors.green, child: Text('2')),
),
Expanded(
flex: 3,
child: ColoredBox(color: Colors.blue, child: Text('3')),
),
],
)
在这个例子中,三个区域的宽度比例为 1:2:3。
4.2 Flexible 灵活空间
Flexible 与 Expanded 类似,但更加灵活。它允许子组件根据自身内容调整大小,只占用剩余空间中的必要部分。
Row(
children: const [
Flexible(
child: Text('这是一个很长的文本,会占据所有可用空间'),
),
Flexible(
child: Text('短文本'),
),
],
)
Flexible 和 Expanded 的区别:
| 特性 | Expanded | Flexible |
|---|---|---|
| 强制填充 | 是,强制子组件填满 | 否,根据子组件大小 |
| flex 参数 | 支持 | 支持 |
| fit 参数 | 仅 FlexFit.tight |
tight 或 loose |
| 使用场景 | 需要强制填充时 | 需要灵活调整时 |
4.3 Spacer 占位组件
Spacer 是一个便捷的占位组件,相当于 Expanded(flex: 1) 的简化写法。
Row(
children: const [
Text('左边'),
Spacer(),
Text('右边'),
],
)
Spacer 也可以指定 flex 参数:
Row(
children: const [
Text('左边'),
Spacer(flex: 2),
Text('中间'),
Spacer(flex: 1),
Text('右边'),
],
)
五、布局约束与溢出处理
5.1 布局溢出问题
当 Row 的子组件总宽度超过父组件的可用宽度时,或者 Column 的子组件总高度超过父组件的可用高度时,会发生布局溢出错误。
// ❌ 这会导致溢出错误
Row(
children: List.generate(
10,
(index) => const Text('这是一个很长的文本'),
),
)
5.2 解决溢出的方法
方法一:使用 Flexible
将可能溢出的子组件包裹在 Flexible 中,让它能够自适应。
Row(
children: [
...List.generate(
10,
(index) => Flexible(
child: Text('文本 $index'),
),
),
],
)
方法二:使用 Expanded
如果希望子组件均匀分配空间,使用 Expanded。
Row(
children: [
...List.generate(
10,
(index) => Expanded(
child: Center(child: Text('$index')),
),
),
],
)
方法三:使用 SingleChildScrollView
如果内容确实需要超出,可以使用滚动视图。
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: List.generate(
10,
(index) => const Text('这是一个很长的文本 '),
),
),
)
5.3 overflow 属性
overflow 属性可以控制溢出时的行为,但这个属性主要用于调试,不建议在生产环境中使用。
Row(
overflow: TextOverflow.fade,
children: const [
Text('这是一个很长的文本'),
],
)
⚠️ 注意:
overflow属性只对文本类型的子组件有效,对于其他类型的子组件没有作用。
六、高级布局技巧
6.1 嵌套布局
通过嵌套 Row 和 Column,可以构建复杂的布局结构。
Column(
children: [
Row(
children: const [
Icon(Icons.person),
SizedBox(width: 8),
Text('用户名'),
],
),
const SizedBox(height: 16),
Row(
children: const [
Icon(Icons.email),
SizedBox(width: 8),
Text('邮箱地址'),
],
),
],
)
这种嵌套结构可以模拟网格布局,构建复杂的表单或信息展示。
6.2 使用 SizedBox 调整间距
SizedBox 是调整组件间距的利器,比使用 padding 更简洁。
Row(
children: const [
Text('第一个'),
SizedBox(width: 16), // 水平间距
Text('第二个'),
],
)
Column(
children: const [
Text('第一行'),
SizedBox(height: 16), // 垂直间距
Text('第二行'),
],
)
6.3 使用 IntrinsicWidth/Height
IntrinsicWidth 和 IntrinsicHeight 可以让子组件根据自身内容决定尺寸。
IntrinsicWidth(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text('短文本'),
Text('这是一个非常非常长的文本'),
Text('中等长度的文本'),
],
),
)
⚠️ 注意:
IntrinsicWidth和IntrinsicHeight会计算所有子组件的尺寸,可能影响性能,谨慎使用。
6.4 使用 Wrap 自动换行
当需要自动换行的布局时,使用 Wrap 组件。
Wrap(
spacing: 8,
runSpacing: 8,
children: List.generate(
10,
(index) => Chip(
label: Text('标签 $index'),
),
),
)
Wrap 与 Row 类似,但会在空间不足时自动换行,非常适合标签列表等场景。
七、实际应用场景
7.1 导航栏
Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Row(
children: [
const Icon(Icons.menu),
const SizedBox(width: 16),
const Expanded(
child: Text('应用标题', style: TextStyle(fontSize: 18)),
),
IconButton(
icon: const Icon(Icons.search),
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.more_vert),
onPressed: () {},
),
],
),
)
7.2 列表项
Container(
padding: const EdgeInsets.all(16),
child: Row(
children: [
CircleAvatar(
radius: 30,
backgroundImage: NetworkImage('https://picsum.photos/100/100'),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text(
'用户名称',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
SizedBox(height: 4),
Text(
'这是用户的简介信息',
style: TextStyle(fontSize: 14, color: Colors.grey),
),
],
),
),
const Icon(Icons.chevron_right),
],
),
)
7.3 卡片内容
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'卡片标题',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
const Text(
'这是卡片的详细内容描述。Row 和 Column 的组合可以轻松创建各种卡片布局。',
style: TextStyle(fontSize: 14, height: 1.5),
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: () {},
child: const Text('取消'),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
),
child: const Text('确认'),
),
),
],
),
],
),
)
7.4 表单布局
Column(
children: [
const TextField(
decoration: InputDecoration(
labelText: '用户名',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 16),
const TextField(
decoration: InputDecoration(
labelText: '密码',
border: OutlineInputBorder(),
),
obscureText: true,
),
const SizedBox(height: 24),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
),
child: const Text('登录'),
),
),
],
)
八、性能优化
8.1 避免过度嵌套
过度嵌套的 Row 和 Column 会影响性能,尽量使用更简洁的布局方式。
// ❌ 过度嵌套
Row(
children: [
Column(
children: [
Row(
children: [
Text('嵌套'),
],
),
],
),
],
)
// ✅ 简化布局
Row(
children: const [
Text('简化'),
],
)
8.2 使用 const
对于不变的布局组件,使用 const 修饰符。
const TitleRow = Row(
children: [
Text('标题', style: TextStyle(fontSize: 20)),
],
);
8.3 合并布局
将多个相邻的布局合并为一个。
// ❌ 多个布局
Column(
children: [
Row(
children: [Text('第一行')],
),
Row(
children: [Text('第二行')],
),
],
)
// ✅ 合并布局
Column(
children: const [
Text('第一行'),
Text('第二行'),
],
)
8.4 使用 LayoutBuilder
对于需要根据父组件约束调整布局的情况,使用 LayoutBuilder。
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 600) {
return Row(children: [Text('宽屏布局')]);
} else {
return Column(children: [Text('窄屏布局')]);
}
},
)
九、完整示例代码
下面是一个完整的 Flutter 应用示例,展示 Row 和 Column 组件的各种效果。
import 'package:flutter/material.dart';
void main() {
runApp(const LayoutDemo());
}
class LayoutDemo extends StatelessWidget {
const LayoutDemo({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'Row & Column 布局演示',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.dark(
primary: const Color(0xFF6366F1),
secondary: const Color(0xFF8B5CF6),
surface: const Color(0xFF1E293B),
background: const Color(0xFF0F172A),
brightness: Brightness.dark,
),
useMaterial3: true,
),
home: const LayoutPage(),
);
}
}
class LayoutPage extends StatelessWidget {
const LayoutPage({super.key});
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF0F172A),
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 标题区域
Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
const Color(0xFF6366F1).withOpacity(0.2),
const Color(0xFF8B5CF6).withOpacity(0.2),
],
),
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: Colors.white.withOpacity(0.1),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'📐 Row & Column',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.white,
letterSpacing: 0.5,
),
),
const SizedBox(height: 8),
Text(
'探索 Flutter 中线性布局的各种技巧',
style: TextStyle(
fontSize: 14,
color: Colors.white.withOpacity(0.7),
height: 1.5,
),
),
],
),
),
const SizedBox(height: 32),
// Row 主轴对齐
_buildSection(
title: 'Row 主轴对齐',
icon: Icons.horizontal_rule,
color: Colors.blue,
child: _buildLayoutCard([
_buildAlignmentRow('start', MainAxisAlignment.start),
const SizedBox(height: 12),
_buildAlignmentRow('center', MainAxisAlignment.center),
const SizedBox(height: 12),
_buildAlignmentRow('end', MainAxisAlignment.end),
const SizedBox(height: 12),
_buildAlignmentRow('spaceBetween', MainAxisAlignment.spaceBetween),
const SizedBox(height: 12),
_buildAlignmentRow('spaceAround', MainAxisAlignment.spaceAround),
const SizedBox(height: 12),
_buildAlignmentRow('spaceEvenly', MainAxisAlignment.spaceEvenly),
]),
),
const SizedBox(height: 24),
// Row 交叉轴对齐
_buildSection(
title: 'Row 交叉轴对齐',
icon: Icons.vertical_align_center,
color: Colors.green,
child: _buildLayoutCard([
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildCrossAlignmentBox('start', CrossAxisAlignment.start),
_buildCrossAlignmentBox('center', CrossAxisAlignment.center),
_buildCrossAlignmentBox('end', CrossAxisAlignment.end),
_buildCrossAlignmentBox('stretch', CrossAxisAlignment.stretch),
],
),
]),
),
const SizedBox(height: 24),
// Column 主轴对齐
_buildSection(
title: 'Column 主轴对齐',
icon: Icons.view_column,
color: Colors.purple,
child: _buildLayoutCard([
SizedBox(
height: 200,
child: _buildAlignmentColumn('spaceEvenly', MainAxisAlignment.spaceEvenly),
),
]),
),
const SizedBox(height: 24),
// Expanded 使用
_buildSection(
title: 'Expanded 使用',
icon: Icons.open_in_full,
color: Colors.orange,
child: _buildLayoutCard([
_buildExpandedRow(),
]),
),
const SizedBox(height: 24),
// Flexible 使用
_buildSection(
title: 'Flexible 使用',
icon: Icons.compress,
color: Colors.pink,
child: _buildLayoutCard([
_buildFlexibleRow(),
]),
),
const SizedBox(height: 24),
// 实际应用
_buildSection(
title: '实际应用示例',
icon: Icons.apps,
color: Colors.cyan,
child: _buildLayoutCard([
_buildListCard(),
const SizedBox(height: 16),
_buildCardLayout(),
]),
),
const SizedBox(height: 80),
],
),
),
),
);
}
Widget _buildSection({
required String title,
required IconData icon,
required Color color,
required Widget child,
}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: color.withOpacity(0.2),
borderRadius: BorderRadius.circular(10),
),
child: Icon(icon, color: color, size: 20),
),
const SizedBox(width: 12),
Text(
title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
],
),
const SizedBox(height: 12),
child,
],
);
}
Widget _buildLayoutCard(List<Widget> children) {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.03),
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: Colors.white.withOpacity(0.05),
),
),
child: Column(
children: children,
),
);
}
Widget _buildAlignmentRow(String label, MainAxisAlignment alignment) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontSize: 12,
color: Colors.white.withOpacity(0.7),
),
),
const SizedBox(height: 8),
Container(
height: 40,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.05),
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisAlignment: alignment,
children: [
_buildBox('A'),
_buildBox('B'),
_buildBox('C'),
],
),
),
],
);
}
Widget _buildAlignmentColumn(String label, MainAxisAlignment alignment) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontSize: 12,
color: Colors.white.withOpacity(0.7),
),
),
const SizedBox(height: 8),
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.05),
borderRadius: BorderRadius.circular(8),
),
child: Column(
mainAxisAlignment: alignment,
children: [
_buildBox('顶部'),
_buildBox('中间'),
_buildBox('底部'),
],
),
),
),
],
);
}
Widget _buildCrossAlignmentBox(String label, CrossAxisAlignment alignment) {
return Column(
children: [
Container(
width: 60,
height: 80,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.05),
borderRadius: BorderRadius.circular(8),
),
child: Row(
crossAxisAlignment: alignment,
children: const [
Icon(Icons.text_fields, size: 16),
],
),
),
const SizedBox(height: 8),
Text(
label,
style: TextStyle(
fontSize: 10,
color: Colors.white.withOpacity(0.7),
),
),
],
);
}
Widget _buildBox(String text) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.3),
borderRadius: BorderRadius.circular(6),
),
child: Text(
text,
style: const TextStyle(fontSize: 12, color: Colors.white),
),
);
}
Widget _buildExpandedRow() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Flex 比例 1:2:3',
style: TextStyle(fontSize: 12, color: Colors.white70),
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
flex: 1,
child: _buildColorBox('1', Colors.red),
),
const SizedBox(width: 8),
Expanded(
flex: 2,
child: _buildColorBox('2', Colors.green),
),
const SizedBox(width: 8),
Expanded(
flex: 3,
child: _buildColorBox('3', Colors.blue),
),
],
),
],
);
}
Widget _buildFlexibleRow() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Flexible 根据内容调整',
style: TextStyle(fontSize: 12, color: Colors.white70),
),
const SizedBox(height: 8),
Row(
children: [
Flexible(
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.pink.withOpacity(0.3),
borderRadius: BorderRadius.circular(8),
),
child: const Text(
'这是一个很长的文本内容,会占据更多空间',
style: TextStyle(fontSize: 12),
),
),
),
const SizedBox(width: 8),
Flexible(
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.purple.withOpacity(0.3),
borderRadius: BorderRadius.circular(8),
),
child: const Text(
'短文本',
style: TextStyle(fontSize: 12),
),
),
),
],
),
],
);
}
Widget _buildColorBox(String text, Color color) {
return Container(
height: 50,
decoration: BoxDecoration(
color: color.withOpacity(0.4),
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Text(
text,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
);
}
Widget _buildListCard() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.05),
borderRadius: BorderRadius.circular(12),
),
child: Row(
children: [
Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: Colors.cyan.withOpacity(0.3),
borderRadius: BorderRadius.circular(25),
),
child: const Icon(Icons.person, color: Colors.white),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'列表项标题',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 4),
Text(
'这是列表项的详细描述信息',
style: TextStyle(
fontSize: 12,
color: Colors.white.withOpacity(0.7),
),
),
],
),
),
const Icon(Icons.chevron_right, color: Colors.white54),
],
),
);
}
Widget _buildCardLayout() {
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFF6366F1), Color(0xFF8B5CF6)],
),
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'卡片布局示例',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
const SizedBox(height: 12),
Text(
'这是使用 Row 和 Column 组合创建的精美卡片布局。通过灵活运用对齐方式和间距控制,可以创建各种复杂的界面结构。',
style: TextStyle(
fontSize: 14,
color: Colors.white.withOpacity(0.9),
height: 1.5,
),
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () {},
style: OutlinedButton.styleFrom(
foregroundColor: Colors.white,
side: const BorderSide(color: Colors.white),
),
child: const Text('取消'),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
foregroundColor: const Color(0xFF6366F1),
),
child: const Text('确认'),
),
),
],
),
],
),
);
}
}
十、总结
Row 和 Column 是 Flutter 布局的基石,掌握它们的使用对于构建复杂界面至关重要。
🎯 核心要点
- 主轴对齐:通过
mainAxisAlignment控制子组件在主轴上的排列 - 交叉轴对齐:通过
crossAxisAlignment控制子组件在交叉轴上的对齐 - Expanded:让子组件填充剩余空间,支持 flex 比例分配
- Flexible:让子组件灵活调整大小,根据内容自适应
- 避免溢出:使用 Expanded、Flexible 或 SingleChildScrollView 解决布局溢出
- 合理嵌套:通过 Row 和 Column 的嵌套构建复杂的布局结构
📚 使用建议
| 场景 | 推荐布局 |
|---|---|
| 导航栏 | Row + Expanded + MainAxisAlignment.spaceBetween |
| 列表项 | Row + CircleAvatar + Expanded + Column |
| 表单 | Column + TextField + SizedBox + ElevatedButton |
| 卡片 | Column + Text + SizedBox + Row(Expanded) |
| 标签列表 | Wrap + spacing + runSpacing |
💡 最佳实践:Row 和 Column 应该作为布局的基本单元,合理使用 Expanded 和 Flexible 来控制空间分配。注意布局溢出问题,提前规划好组件的尺寸和约束。通过练习和实践,你会发现线性布局的强大和灵活性。
更多推荐



所有评论(0)