在这里插入图片描述

🎯欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

📐 本文将带你深入掌握 Flutter 中最基础也是最重要的两个布局组件——Row 和 Column,理解线性布局的精髓。


一、线性布局概述

在 Flutter 的布局体系中,RowColumn 是最基础也最常用的两个布局组件,它们都继承自 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 最小尺寸 需要紧凑布局

⚠️ 注意:当 mainAxisSizemax 时,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 灵活空间

FlexibleExpanded 类似,但更加灵活。它允许子组件根据自身内容调整大小,只占用剩余空间中的必要部分。

Row(
  children: const [
    Flexible(
      child: Text('这是一个很长的文本,会占据所有可用空间'),
    ),
    Flexible(
      child: Text('短文本'),
    ),
  ],
)

FlexibleExpanded 的区别:

特性 Expanded Flexible
强制填充 是,强制子组件填满 否,根据子组件大小
flex 参数 支持 支持
fit 参数 FlexFit.tight tightloose
使用场景 需要强制填充时 需要灵活调整时

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

IntrinsicWidthIntrinsicHeight 可以让子组件根据自身内容决定尺寸。

IntrinsicWidth(
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: const [
      Text('短文本'),
      Text('这是一个非常非常长的文本'),
      Text('中等长度的文本'),
    ],
  ),
)

⚠️ 注意IntrinsicWidthIntrinsicHeight 会计算所有子组件的尺寸,可能影响性能,谨慎使用。

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 来控制空间分配。注意布局溢出问题,提前规划好组件的尺寸和约束。通过练习和实践,你会发现线性布局的强大和灵活性。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐