Flutter 系列教程:布局基础 (上) - `Container`, `Row`, `Column`, `Flex`

欢迎来到 Flutter 布局的世界!如果说 Widget 是乐高积木,那么布局 Widget 就是你用来搭建城堡的说明书和骨架。学会了布局,你就能将独立的组件组合成任何你想要的复杂界面。

今天,我们将聚焦于线性布局,即沿着水平或垂直方向排列组件。

学习目标

  • 掌握 Container Widget,学会如何用它来装饰和约束单个子组件。
  • 理解 Row (水平) 和 Column (垂直) 的主轴 (Main Axis) 与交叉轴 (Cross Axis) 的概念。
  • 学会使用 mainAxisAlignment 和 crossAxisAlignment 来控制子组件的对齐方式。
  • 了解 Flex,以及它与 Row 和 Column 的关系。

1. Container:万能的容器

你可以将 Container 想象成网页开发中的 <div> 标签,它是一个功能极其强大的"盒子"。它既可以包裹一个子组件 (child),也可以通过自身的属性来定义尺寸、边距、背景色、边框等装饰效果。

核心属性

  • child: 容器内包裹的子组件。
  • width, height: 明确指定容器的宽度和高度。
  • color: 容器的背景颜色。
  • padding: 内边距 ,即 child 相对于容器边界的距离。
  • margin: 外边距,即容器相对于其父组件的距离。
  • decoration (BoxDecoration ): 强大的装饰属性,用于设置边框 (border)、圆角 (borderRadius)、阴影 (boxShadow)、渐变 (gradient)等。注意:如果同时设置了 color 和 decoration,color 属性必须定义在 decoration 内部,否则会报错。

代码示例:创建一个带样式的卡片

less 复制代码
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.grey, // 设置一个灰色背景,以凸显 margin
        appBar: AppBar(title: const Text('Container Demo')),
        body: Center(
          child: Container(
            // 如果设置了 decoration,color 必须放在 decoration 里面
            decoration: BoxDecoration(
              color: Colors.white,
              border: Border.all(
                color: Colors.blue,
                width: 2.0,
              ),
              borderRadius: BorderRadius.circular(12.0),
              boxShadow: [
                BoxShadow(
                  color: Colors.black.withOpacity(0.2),
                  spreadRadius: 3,
                  blurRadius: 7,
                  offset: const Offset(0, 3), // changes position of shadow
                ),
              ],
            ),
            width: 250,
            height: 150,
            padding: const EdgeInsets.all(20.0), // 内边距
            margin: const EdgeInsets.all(30.0),  // 外边距
            child: const Text(
              '这是一个漂亮的 Container!',
              style: TextStyle(fontSize: 20),
              textAlign: TextAlign.center,
            ),
          ),
        ),
      ),
    );
  }
}

2. Row & Column:线性布局的核心

Row 和 Column 是 Flutter 中最常用的布局组件,它们允许你将一组子组件 (children) 沿水平或垂直方向进行排列。

  • Row : 将其 children 沿水平方向排列。
  • Column : 将其 children 沿垂直方向排列。

核心概念:主轴 (Main Axis) 与 交叉轴 (Cross Axis)

这是理解 Row 和 Column 的关键!

  • 对于 Row:

    • 主轴 (Main Axis) 是 水平方向 (从左到右)。
    • 交叉轴 (Cross Axis) 是 垂直方向 (从上到下)。
  • 对于 Column:

    • 主轴 (Main Axis) 是 垂直方向 (从上到下)。
    • 交叉轴 (Cross Axis) 是 水平方向 (从左到右)。

核心属性

  • children: 一个 Widget 列表,是需要被排列的子组件。
  • mainAxisAlignment: 控制子组件在主轴 上的对齐方式。
    • MainAxisAlignment.start: 靠前对齐 (默认值)。
    • MainAxisAlignment.end: 靠后对齐。
    • MainAxisAlignment.center: 居中对齐。
    • MainAxisAlignment.spaceBetween: 两端对齐,子组件之间的间隔相等。
    • MainAxisAlignment.spaceAround: 每个子组件左右两侧的间隔相等,所以首尾两个组件到边界的距离是组件之间间隔的一半。
    • MainAxisAlignment.spaceEvenly: 所有子组件之间 以及首尾到边界的间隔完全相等。
  • crossAxisAlignment: 控制子组件在交叉轴 上的对齐方式。
    • CrossAxisAlignment.start: 靠前对齐。
    • CrossAxisAlignment.end: 靠后对齐。
    • CrossAxisAlignment.center: 居中对齐 (默认值)。
    • CrossAxisAlignment.stretch: 拉伸子组件,使其填满交叉轴空间。

代码示例:Row 和 Column 的对齐演示

less 复制代码
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Row & Column Demo')),
        body: Column(
          children: [
            // --- Row 示例 ---
            Container(
              height: 100, // 给 Row 一个高度以观察 CrossAxisAlignment
              color: Colors.yellow,
              child: const Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                  Icon(Icons.star, size: 50),
                  Icon(Icons.star, size: 50),
                  Icon(Icons.star, size: 50),
                ],
              ),
            ),
            
            const Divider(), // 添加一个分割线

            // --- Column 示例 ---
            Container(
              width: 200, // 给 Column 一个宽度以观察 CrossAxisAlignment
              color: Colors.blue,
              child: const Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.stretch, // 拉伸填满宽度
                children: <Widget>[
                  Text('Item 1', textAlign: TextAlign.center, style: TextStyle(fontSize: 24)),
                  Text('Item 2', textAlign: TextAlign.center, style: TextStyle(fontSize: 24)),
                  Text('Item 3', textAlign: TextAlign.center, style: TextStyle(fontSize: 24)),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

动手试试 :将上面代码中的 mainAxisAlignment 和 crossAxisAlignment 的值修改为其他枚举值,然后热重载,亲眼看看布局发生了什么变化!这是最好的学习方式。


3. Flex:Row 和 Column 的"父类"

你可能不知道,Row 和 Column 其实都是 Flex Widget 的"语法糖"。Flex 是一个更底层的组件,它通过一个 direction 属性来决定其子组件的排列方向。

  • Row 等价于 Flex(direction: Axis.horizontal)。
  • Column 等价于 Flex(direction: Axis.vertical)。

那我们为什么不直接用 Flex 呢? 因为 Row 和 Column 的代码可读性更高,意图更明确。在绝大多数情况下,你都应该优先使用 Row 和 Column。只有当你需要动态地 根据某个条件来决定布局是水平还是垂直时,Flex 才会派上用场。

dart 复制代码
// 这是一个 Row
Row(children: <Widget>[...]);

// 它完全等价于
Flex(
  direction: Axis.horizontal,
  children: <Widget>[...],
);

总结

今天我们学习了 Flutter 布局的四大金刚:

  • Container: 用于包裹、装饰和约束单个 Widget 的瑞士军刀。
  • Row: 用于将子组件水平排列。
  • Column: 用于将子组件垂直排列。
  • 主轴/交叉轴 : 是理解 Row 和 Column 对齐方式的钥匙。
  • Flex : 是 Row 和 Column 的底层实现,用于更动态的布局场景。

掌握了这些,你就已经具备了搭建 80% 静态页面的能力。在下一篇教程中,我们将学习如何处理重叠布局 (Stack) 和弹性布局 (Expanded),让你的布局能力再上一个台阶!我们下篇见!

相关推荐
淡淡的香烟18 分钟前
Flutter实现多语言切换
android·flutter·1024程序员节
计算机魔术师35 分钟前
管谷歌的不是Pichai一个人,是一整层AI智能体
前端
米米商聊39 分钟前
图标能点,按钮就可用了吗?键盘、名称与收藏状态
前端·javascript
Younglina1 小时前
三个晚上,我和 WorkBuddy 做了个生图网站
前端·后端·ai编程
xy34531 小时前
Axure 9.0 内联框架加载方式
前端·ui·html·axure·原型·产品设计
陈随易2 小时前
副业搞钱点子之收入查看器
前端·后端
Profile排查笔记2 小时前
浏览器指纹逆向怎么分析:从网络请求追踪到 JavaScript 采集链
前端·人工智能·后端·自动化
hudie7653 小时前
LikeShop 二开最常改的 5 个文件(附改前改后对比)
前端·uni-app·php·个人开发
qetfw3 小时前
Bash 函数与流程控制:read、if、for、case 验证
linux·前端·javascript·bash
鬼手点金4 小时前
从 API 消息到模型 Token:Chat Template
java·前端·javascript·数据库·人工智能·深度学习·1024程序员节