likes
comments
collection
share

Flutter 布局之 Row & Column & Stack

作者站长头像
站长
· 阅读数 4

1 Row Column Stack 简介

Flutter 根据 x y z 三个坐标轴方向分别对应 Row Column Stack 三个Widget, 它们都有一个 Widget 类型的数组 children.

  1. Rowchildren 中的子组件是按照水平方向(即主轴方向)排列的, 还有一个 交叉轴 是垂直于 主轴 方向(即垂直方向), 通过 主轴交叉轴 方向上的对齐方式来控制子组件的分布方式.

  2. Columnchildren 中的子组件是按照垂直方向(即主轴方向)排列的, 还有一个 交叉轴 是垂直于 主轴 方向(即水平方向), 通过 主轴交叉轴 方向上的对齐方式来控制子组件的分布方式.

  3. Stackchildren 中的子组件是按照z轴方向叠起来的, 第一个在最底层, 依次叠加, 飘浮于上方.

接下来的示例代码主体部分不变, 变化的主要是 Widget layoutStyle() 这个函数, layoutStyle() 的实现在各部分的示例中给出, 各部分的效果给出截图, 截图的黑色边框就是模拟器的边框了, 整个模拟器图片比较大, 因此如果不是必须, 就只截一部分.

  • 代码主体部分
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(title: const Text('Layout Demo'),),
        body: Center(
          child: layoutStyle(),
        ),
      ),
    );
  }
}

2 Row

Rowchildren 中的子组件是按照数组中的顺序, 从start开始沿水平方向排列, 所有组件宽度总和不能超过 Row 最大能延伸的宽度, 否则会因为放不下而报错, 并不会像 iOS 原生超出的部分不显示. Row 的高度默认以子组件中最大的高度为准.

注意: 2.1 2.2 2.3 都是在 textDirectionverticalDirection 默认值时的效果, 具体原因在 2.4 2.5 说明, 这两个一般我们也不会去修改.

  • Widget layoutStyle() 函数 我们本例的代码外层 Container 高度设置为 100, 与最大的子组件高度相同, 具体用意会在 crossAxisAlignment 中体现出来.
  Widget layoutStyle() {
    return Container(
      color: Colors.yellow,
      height: 100,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisSize: MainAxisSize.max,
        textDirection: TextDirection.ltr,
        verticalDirection: VerticalDirection.down,
        children: [
          Container(
            color: Colors.grey,
            alignment: Alignment.center,
            width: 60,
            height: 80,
            child: const Text(
              'C 1',
              style: TextStyle(fontSize: 20,),
            ),
          ),
          Container(
            color: Colors.green,
            alignment: Alignment.center,
            width: 100,
            height: 100,
            child: const Text(
              'C 2',
              style: TextStyle(fontSize: 20,),
            ),
          ),
          Container(
            color: Colors.blue,
            alignment: Alignment.center,
            width: 80,
            height: 80,
            child: const Text(
              'C 3',
              style: TextStyle(fontSize: 20,),
            ),
          ),
        ],
      ),
    );
  }

2.1 mainAxisAlignment 主轴对齐

mainAxisAlignment 排列方式默认是 start. 后边给出每种对齐方式一个截图和必要的说明, 只是修改了核心代码部分, 如下

mainAxisAlignment: MainAxisAlignment.start

2.1.1 start

第一个子组件的左边与 Row 的左边对齐, 空出右边的距离, 也是默认方式.

mainAxisAlignment: MainAxisAlignment.start

Flutter 布局之 Row & Column & Stack

2.1.2 center

所有子组件排列到一起, 居中分布, 即第一个子组件左边到 Row 的左边的边距 与 最后一个子组件的右边到 Row 的右边的边距是相同的(m1 == m2).

mainAxisAlignment: MainAxisAlignment.center

Flutter 布局之 Row & Column & Stack

2.1.3 end

最后一个子组件的右边与 Row 的右边对齐, 空出左边的距离.

mainAxisAlignment: MainAxisAlignment.end

Flutter 布局之 Row & Column & Stack

2.1.4 spaceBetween

第一个子组件的左边与 Row 的左边对齐, 最后一个子组件的右边与 Row 的右边对齐, 剩余的距离平均分给组件之间的间距. 如果剩余总宽度是 w, 子组件个数为 n, 则间距 s 计算公式为 s = w / (n - 1).

mainAxisAlignment: MainAxisAlignment.spaceBetween

Flutter 布局之 Row & Column & Stack

2.1.5 spaceAround

假设有 n 个子组件, 剩余总宽度是 w, 把剩余的平均分成 n, 每个子组件分到 w/n, 然后分布再自身左右两边, 即 w/2n, 类似于外边距, 此示例中的间距最终比例为 1:2:2:1, 组件之间的间距是 w/n, 第一个和最后一个边距是 w/2n

mainAxisAlignment: MainAxisAlignment.spaceAround

Flutter 布局之 Row & Column & Stack

2.1.6 spaceEvenly

组件的间距和组件的边距是相等的. 假设有 n 个子组件, 剩余总宽度是 w, 每个距离是 w/(n + 1)

mainAxisAlignment: MainAxisAlignment.spaceEvenly

Flutter 布局之 Row & Column & Stack

2.2 crossAxisAlignment 交叉轴对齐

crossAxisAlignment 默认是 center, 后边给出每种对齐方式一个截图和必要的说明, 只是修改了核心代码部分, 如下

crossAxisAlignment: CrossAxisAlignment.center,

2.2.1 start

所有子组件的顶部与 Row 的顶部对齐.

crossAxisAlignment: CrossAxisAlignment.start,

Flutter 布局之 Row & Column & Stack

2.2.2 center

所有子组件垂直居中, 中心点在同一第水平线上.

crossAxisAlignment: CrossAxisAlignment.center,

Flutter 布局之 Row & Column & Stack

2.2.3 end

所有子组件的底部与 Row 的底部对齐.

crossAxisAlignment: CrossAxisAlignment.end,

Flutter 布局之 Row & Column & Stack

2.2.4 stretch

将所有子组件的高度拉伸到与 Row 相同的高度, 此时 Row 的高度已经不是以高度最大那个组件为准了, 只要 Row 在交叉轴方向上有扩大的空间, 就会被最大限度的撑开. 此示例设置外层 Container 的高度, 就是因为不设置的话会填满屏幕剩余的高度, 所以也给出了将高度改为 200 的效果,

crossAxisAlignment: CrossAxisAlignment.stretch,

Flutter 布局之 Row & Column & Stack

  • 将高度改为 200 的效果

Flutter 布局之 Row & Column & Stack

2.2.5 baseline

baseline 简单理解就是文字的底部对齐. 但是当 crossAxisAlignment 被设置为 baseline 时, 必须设置 RowtextBaseline 属性, 这是一个枚举值, 有两个 case, 分别是 alphabetic -> 英文, ideographic -> 中文, 中英混合的时候效果就不是很好了.

此示例需要我们先把 C 2 的字号改为 40, C 3 的字号改为 80, 才能明显看出效果.

crossAxisAlignment: CrossAxisAlignment.baseline,
// alphabetic 英文
// ideographic 中文
textBaseline: TextBaseline.alphabetic,

Flutter 布局之 Row & Column & Stack

2.3 mainAxisSize 主轴尺寸

mainAxisSize 就是主轴方向上的尺寸, 其实就是宽度,

2.3.1 max

默认是 max, 设置为 max, 向右最大限度扩张, 此示例就会到屏幕右边, 就是整个屏幕的宽度.

mainAxisSize: MainAxisSize.max

Flutter 布局之 Row & Column & Stack

2.3.2 min

设置为 min, 就是宽度刚刚好是所有组件宽度的总和. 因为外层的 Container 是居中显示的, 所以最终 Row 就在屏幕中间显示.

mainAxisSize: MainAxisSize.min

Flutter 布局之 Row & Column & Stack

2.4 textDirection 水平排列方向

textDirection 控制子组件水平方向的起始位置, 是一个枚举属性, 默认为 ltr, TextDirection 枚举有 ltrrtl 两个值.

  • ltr: 表示水平方向的 start 在左边, end 在右边,
  • rtl: 表示水平方向的 start 在右边, end 在左边.

2.4.1 ltr

默认设置.

mainAxisAlignment: MainAxisAlignment.start,
textDirection: TextDirection.ltr,

Flutter 布局之 Row & Column & Stack

2.4.2 rtl

同时把 mainAxisAlignment 设置为 end.

mainAxisAlignment: MainAxisAlignment.end,
textDirection: TextDirection.rtl,

Flutter 布局之 Row & Column & Stack

2.5 verticalDirection 垂直排列方向

verticalDirection 控制子组件垂直方向的起始位置, 是一个枚举属性, 默认为 down, VerticalDirectionupdown 两个值. 在 Row 中它的设置会影响到 crossAxisAlignment.

  • down: 表示垂直方向的 start 在顶部, end 在底部.
  • up: 表示垂直方向的 start 在底部, end 在顶部.

2.5.1 down

默认设置, start 在上边, end 在下边..

crossAxisAlignment: CrossAxisAlignment.end,
verticalDirection: VerticalDirection.down,

Flutter 布局之 Row & Column & Stack

2.5.2 up

start 在下边, end 在上边.

crossAxisAlignment: CrossAxisAlignment.end,
verticalDirection: VerticalDirection.up,

Flutter 布局之 Row & Column & Stack

3 Column

Columnchildren 中的子组件是按照数组中的顺序, 从start沿垂直方向排列, 所有组件高度总和不能超过 Column 最大能延伸的高度, 否则会因为放不下而报错, 并不会像 iOS 原生超出的部分不显示. Column 的宽度默认以子组件中最大的宽度为准.

注意: Column 是不能滚动, 所以最大高度也不能超过屏幕. 2.1 2.2 2.3 都是在 textDirectionverticalDirection 默认值时的效果, 具体原因在 2.4 2.5 说明, 这两个一般我们也不会去修改.

我们本例的代码外层 Container 宽度设置为 150, 与最大的子组件宽度相同, 具体用意会在 crossAxisAlignment 中体现出来.

ColumnRow 只是排列方向不同, 原理是一样的. 所以就不做过多阐述了, 直接上图看效果.

  • Widget layoutStyle() 函数
  Widget layoutStyle() {
    return Container(
      width: 150,
      color: Colors.yellow,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisSize: MainAxisSize.max,
        textDirection: TextDirection.ltr,
        verticalDirection: VerticalDirection.down,
        children: [
          Container(
            color: Colors.grey,
            alignment: Alignment.center,
            width: 80,
            height: 80,
            child: const Text(
              'C 1',
              style: TextStyle(fontSize: 20,),
            ),
          ),
          Container(
            color: Colors.green,
            alignment: Alignment.center,
            width: 150,
            height: 150,
            child: const Text(
              'C 2',
              style: TextStyle(fontSize: 20,),
            ),
          ),
          Container(
            color: Colors.blue,
            alignment: Alignment.center,
            width: 100,
            height: 120,
            child: const Text(
              'C 3',
              style: TextStyle(fontSize: 20,),
            ),
          ),
        ],
      ),
    );
  }

3.1 mainAxisAlignment 主轴对齐

改变的核心代码是主轴对齐方式, 如下

mainAxisAlignment: MainAxisAlignment.start,

3.1.1 start

mainAxisAlignment: MainAxisAlignment.start,

Flutter 布局之 Row & Column & Stack

3.1.2 center

mainAxisAlignment: MainAxisAlignment.center,

Flutter 布局之 Row & Column & Stack

3.1.3 end

mainAxisAlignment: MainAxisAlignment.end,

Flutter 布局之 Row & Column & Stack

3.1.4 spaceBetween

mainAxisAlignment: MainAxisAlignment.spaceBetween,

Flutter 布局之 Row & Column & Stack

3.1.5 spaceAround

mainAxisAlignment: MainAxisAlignment.spaceAround,

Flutter 布局之 Row & Column & Stack

3.1.6 spaceEvenly

mainAxisAlignment: MainAxisAlignment.spaceEvenly,

Flutter 布局之 Row & Column & Stack

3.2 crossAxisAlignment 交叉轴对齐

改变的核心代码是主轴对齐方式, 如下

crossAxisAlignment: CrossAxisAlignment.center,

3.2.1 start

crossAxisAlignment: CrossAxisAlignment.start,

Flutter 布局之 Row & Column & Stack

3.2.2 center

crossAxisAlignment: CrossAxisAlignment.center,

Flutter 布局之 Row & Column & Stack

3.2.3 end

crossAxisAlignment: CrossAxisAlignment.end,

Flutter 布局之 Row & Column & Stack

3.2.4 stretch

crossAxisAlignment: CrossAxisAlignment.stretch,

Flutter 布局之 Row & Column & Stack

3.2.4 baseline

baseline 设置之后, 与 start 效果相同, 我个人理解好像没什么用, 在 Column 还没有找到使用场景, 暂时先不做说明, 如果哪位小伙伴知道使用场景, 请不吝赐教, 表示感谢.

3.3 mainAxisSize 主轴尺寸

改变的核心代码是主轴对齐方式, 如下

mainAxisSize: MainAxisSize.max,

3.3.1 max

mainAxisSize: MainAxisSize.max,

Flutter 布局之 Row & Column & Stack

3.3.2 min

mainAxisSize: MainAxisSize.min,

Flutter 布局之 Row & Column & Stack

3.4 textDirection 水平排列方向

crossAxisAlignment: CrossAxisAlignment.end,
textDirection: TextDirection.rtl,

Flutter 布局之 Row & Column & Stack

3.5 verticalDirection 垂直排列方向

mainAxisAlignment: MainAxisAlignment.end,
verticalDirection: VerticalDirection.up,

Flutter 布局之 Row & Column & Stack

4 Stack

Stackchildren 中的子组件是按照z轴方向叠起来的, 第一个在最底层, 依次叠加, 飘浮于上方.

textDirection 控制水平方向 startend 的位置, 在 Row 部分已经说明, 此处就不再说了.

宽按照最宽的子组件为准, 高按照最高的子组件为准.

 Widget layoutStyle() {
    return Container(
      color: Colors.yellow,
      padding: const EdgeInsets.all(20),
      child: Stack(
        alignment: AlignmentDirectional.topStart,
        textDirection: TextDirection.ltr,
        fit: StackFit.loose,
        clipBehavior: Clip.hardEdge,
        children: [
          Container(
            color: Colors.green,
            alignment: Alignment.center,
            width: 150,
            height: 100,
            child: const Text(
              'C 1',
              style: TextStyle(fontSize: 20,),
            ),
          ),
          Container(
            color: Colors.grey,
            alignment: Alignment.center,
            width: 100,
            height: 150,
            child: const Text(
              'C 2',
              style: TextStyle(fontSize: 20,),
            ),
          ),
          Container(
            color: Colors.blue,
            alignment: Alignment.center,
            width: 50,
            height: 50,
            child: const Text(
              'C 3',
              style: TextStyle(fontSize: 20,),
            ),
          ),
        ],
      ),
    );
  }

4.1 alignment 对齐方式

对齐方式系统给出 9 种常用方式, 同时也可以根据自己的需求, 来设置 xy轴的比例. textDirection 默认为 ltr , 水平方向 start 在左边, end 在右边, 当设置 rtlstartend 的位置互换.

修改的核心代码如下:

alignment: AlignmentDirectional.topStart,

4.1.1 topStart

所有子组件左上角对齐.

alignment: AlignmentDirectional.topStart,

Flutter 布局之 Row & Column & Stack

4.1.2 topCenter

所有子组件顶部水平中心点对齐.

alignment: AlignmentDirectional.topCenter,

Flutter 布局之 Row & Column & Stack

4.1.3 topEnd

所有子组件右上角对齐.

alignment: AlignmentDirectional.topEnd,

Flutter 布局之 Row & Column & Stack

4.1.4 centerStart

所有子组件左边垂直中心点对齐.

alignment: AlignmentDirectional.centerStart,

Flutter 布局之 Row & Column & Stack

4.1.5 center

所有子组件中心点对齐.

alignment: AlignmentDirectional.center,

Flutter 布局之 Row & Column & Stack

4.1.6 centerEnd

所有子组件右边垂直中心点对齐.

alignment: AlignmentDirectional.centerEnd,

Flutter 布局之 Row & Column & Stack

4.1.7 bottomStart

所有子组件左下角对齐.

alignment: AlignmentDirectional.bottomStart,

Flutter 布局之 Row & Column & Stack

4.1.8 bottomCenter

所有子组件底部中心对齐.

alignment: AlignmentDirectional.bottomCenter,

Flutter 布局之 Row & Column & Stack

4.1.9 bottomEnd

alignment: AlignmentDirectional.bottomEnd,

Flutter 布局之 Row & Column & Stack

4.1.10 自定义

alignment: const AlignmentDirectional(-0.5, -0.5),

Flutter 布局之 Row & Column & Stack

4.2 textDirection

ltr 默认设置上边已经全部列出了, 就不再重复了, 下面主要看一下 rtl 的情况, 主要就是 startend 位置互换, 只展示期中一种情况, 其他依次类推, 大家自己体验就好.

4.2.1 rtl

所有子组件右上角对齐.

alignment: AlignmentDirectional.topStart,
textDirection: TextDirection.rtl,

Flutter 布局之 Row & Column & Stack

Stack 其他几个属性的用法和场景还没有研究, 后续找时间再探索吧...

总结

Row Column Stack 主要用于多个子组件的布局, 是 Flutter 中常用的布局组件, 像下图这种就很适合, 这个是自己随便画的, 不要介意😄.

Flutter 布局之 Row & Column & Stack