前言:

前面的文章介绍了Flutter的基础使用,有了基础知识,就可以使用 Flutter 提供的组件设计各种界面。本文围绕 Flutter 中常用的布局组件展开,梳理了基础容器、线性布局、弹性布局、流式布局与层叠布局的核心用法,帮助读者建立清晰的页面布局思路。

目录

布局组件基础介绍

Container

Center

Align

Padding

Column

Row

Flex

Wrap

Stack / Positioned


 

布局组件基础介绍

Flutter 提供了丰富的布局组件用来构建各种用户界面。部分核心组件如下表

组件类别 核心组件 主要特点和使用场景
基础容器 Container、Center、Align、Padding 提供装饰、对齐、边距等基础样式和布局控制。使用频率高。
线性布局 Row、Column 在水平或垂直方向线性排列子组件,使构建页面的基础。
弹性布局 Flex、Expanded、Flexible 按照比例分配剩余空间,实现自适应布局。常与 Row 和 Column 搭配使用
层叠布局 Stack、Positioned 让子组件重复堆叠,进而实现如图片上叠文字、悬浮按钮等效果
流式布局 Wrap、Flow 当主轴空间不足时自动换行或换列,常用于标签、滤镜等动态宽高内容的排列
滚动布局 ListView、GridView 提供可滚动的列表或网格视图,高效展示大量数据

Container

Container 是功能丰富的布局组件,是一个多功能组合容器。

尺寸控制

可通过多种方式定义大小,有明确优先级规则:父组件约束 > Container 显式约束 > 自适应组件大小。通过向 width 和 height 属性传入 double.infinity,可以使对应宽高占满能占满的最大值。

装饰系统

通过 decoration 属性实现视觉效果,和 color 属性互斥。decoration 属性传入的类型为 BoxDecoration()。其中可以定义多种装饰类型,如背景色,边框弧度,边框样式等;

decoration: BoxDecoration(
    color: Colors.blue,
    borderRadius: BorderRadius.circular(15),
    border: Border.all(width: 3, color: Colors.amber),
)

边框弧度通过 borderRadius 属性进行设置,圆角属性为 BorderRadius.circular(圆角弧度)

边框样式

通过 border 属性进行设置,接收 Border 类型,通过 width 设置宽度,color 设置颜色。

布局控制

提供内外边距和对齐方式。其中:

  • margin:外边距,接收 EdgeInsets 类型。
  • padding:内边距,接受 EdgeInsets 类型。

可选变化

支持绘制时进行矩形变换,如旋转、倾斜、平移。

通过 transform 属性对 Container 进行旋转,传入 Matrix4,通过 rotationX() 等方法进行旋转,传入参数的单位为弧度。

常见属性

属性类别 关键属性 作用说明
布局定位 alignment 控制其 child 在组件内部对齐的方式。
尺寸控制 width / height / constraints 设置容器的宽度和高度 / 为容器设置尺寸约束。
间距留白 padding / margin 按照比例分配剩余空间,实现自定义布局,常与 Row / Column 配合使用。
装饰效果 color / decoration 为容器设置简单的背景颜色 / 为容器设置复杂的背景装饰。
变换效果 transform 对容器及其内容进行矩阵变换。
子组件 child 容器内包含的唯一直接子组件。
Container(
    alignment: Alignment.center,
    margin: EdgeInsets.all(20),
    transform: Matrix4.rotationZ(0.05),
    width: 200,
    height: 200,
    // color: Colors.blue,
    decoration: BoxDecoration(
        color: Colors.blue,
        borderRadius: BorderRadius.circular(15),
        border: Border.all(width: 3, color: Colors.amber),
    ),
    child: Text(
        "Hello, Container!",
        style: TextStyle(color: Colors.white),
    ),
)

Center

Center 组件将其子组件在父组件的空间内进行水平和垂直方向上的居中排列。在父组件是 Container 的情况下,也可以直接使用 alignment: Alignment.Center 实现元素居中。

Center(
    child: Container(
        width: 100,
        height: 100,
        color: Colors.blue,
        child: Center(child: Text("居中内容")),
    ),
)

应用场景

  • 页面内容整体居中,如将一个登录表单或一个加载中提示图在页面中央显示;
  • Center 不能设置宽高,Center 的最终大小取决于父组件传递给他的约束,会尽可能向父组件申请尽可能大的空间
  • 实现宽高固定且居中的组件:使用 Center 包裹一个具有固定宽高的子组件 (Container / SizeBox);

Align

Center 主要用于居中对齐,而 Align 可以精确控制其子组件在父容器空间中的对齐位置。Center 实际上就是 Align 的一种特殊形式,他继承自 Align,相当于将 alignment 属性设为 Align.center。

当需要将一个组将放在父容器的特定角落时,选择使用 Align。

通过 Icon 组件,可以实现在页面中放入 Flutter 内置图标,同时可以使用 size 和 color 指定图标的大小和颜色等信息。

Icon(
    Icons.star, 
    size: 150, 
    color: Colors.amber
)

属性

  • alignment:对齐方式,子组件在父容器中的对齐方式。
  • widthFactor:宽度因子,Align 的宽度是子组件宽度乘以该因子。
  • heightFactor:高度因子,Align 的高度是子组件高度乘以该因子。

宽度因子和高度因子在动态布局中很有用。

Align(
    alignment: Alignment.center,
    widthFactor: 3,
    heightFactor: 5,
    child: Icon(Icons.star, size: 50, color: Colors.amber),
),

Padding

Padding 的作用是为子组件添加内边距。该组件只有两个属性,child 用于接收子组件,而 padding 用于设置内边距的大小。

padding 属性的类型为 EdgeInsets。在 Padding 中,该属性是必须的,其定义了内边距的大小和方向。

当四个方向设置相同间距时,使用 EdgeInsets.all()

Padding(
    padding: EdgeInsetsGeometry.all(10),
    child: Container(color: Colors.blue),
),

当需要设置某个或某几个方向的 Padding 时,使用 EdgeInsets.only(top, bottom, left, right)

Padding(
    padding: EdgeInsetsGeometry.only(top: 10, bottom: 10),
    child: Container(color: Colors.blue),
),

当想要设置的 Padding 方向恰好对称时,可以使用 EdgeInsets.only(vertical, horizontal)

Padding(
    padding: EdgeInsetsGeometry.symmetric(vertical: 10, horizontal: 20),
    child: Container(color: Colors.blue),
)

除了使用 Padding 外,还有很多方式用于添加内边距,他们的使用方法都是相同的:

  • Container 容器的 padding 属性;
  • decoration 属性的 BoxDecoration 类中,也允许添加 padding 属性。

当不需要使用 Container 的其他功能,只需要 padding 时,优先选择 Padding 而非 Container。

Column

Column 用于垂直排列其子组件的核心布局容器,其中所有子组件都会按纵向的方式排列。几乎所有需要垂直排列元素的界面中都能看到他,如:表单列表、设置列表、卡片布局、图文混排 等。

注意,Column 本身不支持滚动,如果内容超出,需要使用 ListView 或 SingleChildScrollView 包裹;同时,父组件的大小直接影响到 Column 的最终大小和子组件布局行为,需要明确尺寸约束;代码书写时,需要避免过度嵌套,嵌套过深会影响性能并增加代码维护难度。

Column 的默认主轴是垂直方向的,交叉轴是水平方向的。

属性 类型 作用说明
mainAxisAlignment MainAxisAlignment 控制子组件在主轴上的排列方向,如顶部对齐、居中或均匀分布。
crossAxisAlignment CrossAxisAlignment 控制子组件在交叉轴上的排列方向,如左对齐、右对齐或拉伸填满。
mainAxisSize MainAxisSize 决定 Column 本身在垂直方向上的尺寸策略:占满所有空间或仅包裹子组件内容。
children List<Widget> 需要被垂直排列的子组件列表。

Column 的 mainAxisAlignment 和 crossAxisAlignment 都支持多种排列方式;

在 mainAxisAlignment,支持的排列方式如下:

  • spaceEvently
  • spaceAround
  • spaceBetween
  • start
  • end
  • center

同时,在排列的过程中,可以使用 margin 外边距控制各个组件之间的距离 (参考前端)。

Column(
    // mainAxisAlignment: MainAxisAlignment.spaceBetween,
    // mainAxisAlignment: MainAxisAlignment.spaceAround,
    // mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    mainAxisAlignment: MainAxisAlignment.center,
    children: [
        Container(
            width: 100,
            height: 100,
            margin: EdgeInsets.only(top: 10),
            color: Colors.blue,
        ),
        Container(
            width: 100,
            height: 100,
            margin: EdgeInsets.only(top: 10),
            color: Colors.blue,
        ),
        Container(
            width: 100,
            height: 100,
            margin: EdgeInsets.only(top: 10),
            color: Colors.blue,
        ),
    ],
),

crossAxisAlignment 支持的排列方式如下:

  • start
  • center
  • end
  • baseline
  • stretch

可以使用这些属性指定位置。

crossAxisAlignment: CrossAxisAlignment.start

Row

类似于 Column,用于水平排列其子组件的核心布局容器。属性列表与 Column 相同。

对于 Row,几乎所有需要水平排列元素的界面都需要使用它,如导航栏、图文混排、表单行等。

类似的,Row 本身不支持滚动,如果内容超出,需要使用 ListView 或 SingleChildScrollView 包裹;父组件大小直接影响 Row 的最终大小和子组件布局行为。

Row(
    mainAxisAlignment: MainAxisAlignment.spaceAround,
    children: [
        Container(width: 100, height: 100, color: Colors.blue),
        Container(width: 100, height: 100, color: Colors.blue),
        Container(width: 100, height: 100, color: Colors.blue),
    ],
)

Flex

Flex 组件允许沿一个主轴 (水平或垂直) 排列其子组件,灵活的控制这些子组件在主轴上的尺寸比例和空间分配,其可以看作 Column 组件和 Row 组件的结合体。其常用分布属性参见 Column。

Flex 布局受其父组件传递的约束影响,使用时需要确保父组件提供了适当的布局约束。

通过 direction 属性,可以设定 Flex 组件的主轴方向;Axis.horizontal 为水平方向,Axis.vertical 为垂直方向。

Flex 的子组件常使用 Expanded 或 Flexible 来控制空间分配,通过 flex 属性分配 Flex 组件空间,flex 属性默认为 1。

Expanded 和 Flexible 都可以实现空间适应的效果,但 Expanded 组件强制子组件填满所有剩余空间,而 Flexible 默认使用最小子组件空间。如果需要 Flexible 也强制填满空间,需要设置 fit 属性为 FlexFit.tight 以开启。

Flex(
    direction: Axis.vertical,
    children: [
        Expanded(
            flex: 2,
            child: Container(width: 100, height: 100, color: Colors.red),
        ),
        Expanded(
            flex: 1,
            child: Container(width: 100, height: 100, color: Colors.green),
        ),
    ],
),

Wrap

Wrap 是流式布局组件,当子组件在主轴方向上排列不下时,会自动换行 / 换列。对于 Column / Row / Flex,内容超出均不会换行。

Wrap 组件更像是 Flex 组件加了换行特性。当子组件内容是根据数据动态生成的时,使用 Wrap 可以保证布局始终适配。

属性 常用值 作用说明
direction Axis.horizontal / Axis.vertical 设置主轴方向,即排列方向
spacing 数值 主轴方向上,子组件之间的间距
runSpacing 数值 交叉轴方向上,行 / 列之间的间距
alignment WrapAlignment 子组件在主轴方向上的对齐方式
runAlignment WrapAlignment 交叉轴方向上的对齐方式
Wrap(
    spacing: 5,
    runSpacing: 5,
    alignment: WrapAlignment.spaceAround,
    direction: Axis.horizontal,
    children: getList(),
),

当需要批量生成组件时,可以利用函数,同时在函数中使用 List.generate(nums, function) 方法进行批量生产。

List<Widget> getList() {
    return List.generate(10, (index) {
        return Container(width: 100, height: 100, color: Colors.blue);
    });
}

Stack / Positioned

Stack 是层叠布局组件,允许将多个子组件按照 Z 轴方向进行叠加排列。直接使用 Stack 堆叠时,children 数组中靠后的元素覆盖在在靠前元素的上面。Stack 和 Positioned 元素适用于几乎所有需要叠加效果的界面上,如图像上的水印、提示弹窗、悬浮按钮等。

Stack 也需要注意明确尺寸约束,父组件的大小直接影响 Stack 的最终大小和子组件的布局行为。

如果想要 Stack 拥有大小,可以使用 Container 组件包裹 Stack。

Container(
    width: double.infinity,
    height: double.infinity,
    color: Colors.amber,
    child: Stack(...),
),
属性 类型 作用说明
alignment AlignmentGeometry 控制非定位子组件在 Stack 内的对齐方式,默认左上角
fit StackFit 控制非定位子组件如何适应 Stack 的尺寸
clipBehavior Clip 控制子组件超出 Stack 边界时的裁剪方式
children List<Widget> 需要被层叠排列的子组件列表
Stack(
    alignment: Alignment.topRight,
    children: [
        Container(width: 300, height: 300, color: Colors.blue),
        Container(width: 200, height: 200, color: Colors.red),
        Container(width: 100, height: 100, color: Colors.amber),
        Container(width: 50, height: 50, color: Colors.green),
    ],
),

Positioned 组件是 Stack 的黄金搭档,可以实现对子组件的精确定位控制。Positioned 必须为 Stack 的直接子组件,可以不用 Positioned,但是如果需要使用必须作为直接子组件。

Positioned 通过 left、right、top、bottom 将子组件放置在 Stack 的角落或边缘。当 Postion 同时设置 left & right / top & bottom 时,会拉伸组件大小至满足 Positioned 定位属性宽度。

Stack(
    children: [
        Container(width: 300, height: 300, color: Colors.grey),
        Positioned(
            left: 20,
            top: 20,
            child: Container(width: 100, height: 100, color: Colors.red),
        ),
        Positioned(
            right: 20,
            bottom: 20,
            child: Container(width: 100, height: 100, color: Colors.blue),
        ),
        Positioned(
            right: 20,
            left: 20,
            bottom: 0,
            child: Container(width: 10, height: 10, color: Colors.green),
        ),
    ],
),

总结:

Flutter 的布局体系看似组件众多,但本质上是在解决空间如何分配、元素如何排列、内容如何适配等问题。从 Container、Center、Align、Padding 这类基础组件,到 Row、Column、Flex 这样的主轴布局组件,再到 Wrap、Stack、Positioned 这种更偏场景化的布局方式,实际上构成了一套由简单到灵活、由基础到复杂的完整布局能力。

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

 

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐