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),让你的布局能力再上一个台阶!我们下篇见!

相关推荐
骑着蜗牛撵大象32735 分钟前
Qt 事件机制详解:从 QEvent 派生类到事件过滤器的全景指南
前端·python
传奇开心果编程41 分钟前
【现代声明式UI学与练】第1课 从命令式UI到声明式UI
学习·flutter·ui·swiftui·react·android jetpack
qq_2518364571 小时前
理发管理系统 —— 会员模块
开发语言·前端·python·flask
Frag0ut1 小时前
2027 年浏览器展望:Chrome 与 Edge 的 AI 智能体进化方向
前端·人工智能·chrome·edge·浏览器·新功能
计算机魔术师2 小时前
从AI绘图鼻祖到音乐版权破局者,Stability AI如何被三大唱片巨头「收编」
前端
奕鼎竜瑆2 小时前
Chrome 插件开发实战指南:从入门到发布
前端·chrome
广州华水科技2 小时前
水库北斗GNSS变形监测系统及单北斗形变监测一体机应用解析
前端
可乐鸡翅yeah_3 小时前
fmp4 碎片 MP4 格式 HLS 流,和传统 TS 分片有什么不一样
开发语言·javascript·ios·音视频·safari·m3u8·m3u8在线播放
anew___4 小时前
《从零手写操作系统 (20):ELF加载器——让OS读懂现代编译器》
java·服务器·前端
ss2734 小时前
AI全栈实战 | 2.3-01 组件库实战:Element Plus 怎么搭出专业界面,过度封装为什么成维护负担
前端·javascript·elementui·vue