阅读 225

Flutter 中 Column、Row、Flex 详解一文聊透 | Flutter Widgets

这是我参与更文挑战的第10天,活动详情查看: 更文挑战

前言

前一篇我们聊了 Wrap 主要实现根据子项大小的不同实现自动换行的布局,今天聊的 Row、Column、Flex 看名字就知道是横竖向布局。与 Wrap 的区别就在于超过横竖向布局大小约束后不能够自动换行,所以这就是我们之前为什么先聊 Wrap 再聊 Row、Column、Flex 的原因,让大家真正知道什么时候该用什么 Widget,充分理解他们的核心区别。

Row(横向-行布局)

这里和 Wrap 一样我们只需要传一个 List children ,即可实现填充 Row

Row(
  // 构建 3 个 Item
  children: List.generate(3, (index) => getItem(index)),
)
复制代码

getItem 实现

/// 获取子项目
Widget getItem(int index) {
  return Container(
    // 宽高设置 60
    width: 60,
    height: 60,
    // 设置背景色
    color: Colors.orange.shade200,
    // 设置间隙
    margin: EdgeInsets.all(2),
    // 设置子项居中
    alignment: Alignment.center,
    // 设置子项
    child: Text('$index'),
  );
}
复制代码

看效果

这里我们稍微做一下装饰,方面后面出对比效果

// 添加背景
child: Container(
  height: 375,
  width: double.maxFinite,
  // 设置背景颜色
  color: Colors.green.shade400,
  // 居中
  alignment: Alignment.center,
  // 构建 Row 布局
  child: Row(
    // 构建 5 个 Item
    children: List.generate(3, (index) => getItem(index)),
  ),
)
复制代码
Row 3 个Row 10 个Wrap 10 个
image.pngimage.pngimage.png

这里忽略对齐方式,只看排列效果,当我们需要自动换行时使用 Wrap

mainAxisSize (主轴大小)

这里我们为了方便我们开启 DevTools 中的 Widget Inspector 可以非常方便的为我们确定 Widget 的大小、属性、结构等一些列操作。

  • max 则横向填充满
  • min 则横向根据子项总大小填充
MainAxisSize.max(默认)MainAxisSize.min
image.pngimage.png

mainAxisAlignment(主轴对齐方式)

MainAxisAlignment.start(默认)MainAxisAlignment.centerMainAxisAlignment.end
image.pngimage.pngimage.png
MainAxisAlignment.spaceBetweenMainAxisAlignment.spaceAroundMainAxisAlignment.spaceEvenly
image.pngimage.pngimage.png

crossAxisAlignment(次轴对齐方式)

这里为了看到效果我们去掉 Container 的 alignment,此时 Row 是和 Container 是一样大的

Container(
  height: 375,
  width: double.maxFinite,
  // 设置背景颜色
  color: Colors.green.shade400,
  // 居中
  // alignment: Alignment.center,
  // 构建 Row 布局
  child: Row(
    mainAxisSize: MainAxisSize.max,//默认
    mainAxisAlignment: MainAxisAlignment.start,// 默认
    crossAxisAlignment: CrossAxisAlignment.center,// 默认
    // 构建 3 个 Item
    children: List.generate(3, (index) => getItem(index)),
  ),
)
复制代码

image.png

CrossAxisAlignment.startCrossAxisAlignment.center(默认)CrossAxisAlignment.end
image.pngimage.pngimage.png
CrossAxisAlignment.stretchCrossAxisAlignment.baseline备注
image.pngimage.png设置 baseline 时,必须配合 textBaseline 进行设置。

Column(竖向-列布局)

其实 Column 和 Row 是对应的一个竖向一个横向,属性肯定也是一样的,接下来我们一起来看一下吧

看效果

Container(
  height: 375,
  width: double.maxFinite,
  // 设置背景颜色
  color: Colors.green.shade400,
  // 居中
  alignment: Alignment.center,
  // 构建 Column 布局
  child: Column(
    // 构建 3 个 Item
    children: List.generate(3, (index) => getItem(index)),
  ),
)
复制代码

mainAxisSize (主轴大小)

这里我们依然开启 Widget Inspector 辅助查看

  • max 则竖向填充满
  • min 则竖向根据子项总大小填充
MainAxisSize.max(默认)MainAxisSize.min
image.pngimage.png

mainAxisAlignment(主轴对齐方式)

MainAxisAlignment.start(默认)MainAxisAlignment.centerMainAxisAlignment.end
image.pngimage.pngimage.png
MainAxisAlignment.spaceBetweenMainAxisAlignment.spaceAroundMainAxisAlignment.spaceEvenly
image.pngimage.pngimage.png

crossAxisAlignment(次轴对齐方式)

这里为了看到效果我们去掉 Container 的 alignment,此时 Column 是和 Container 是一样大的

Container(
  height: 375,
  width: double.maxFinite,
  // 设置背景颜色
  color: Colors.green.shade400,
  // 居中
  // alignment: Alignment.center,
  // 构建 Column 布局
  child: Column(
    mainAxisSize: MainAxisSize.max,
    mainAxisAlignment: MainAxisAlignment.start,
    // 构建 3 个 Item
    children: List.generate(3, (index) => getItem(index)),
  ),
)
复制代码
CrossAxisAlignment.startCrossAxisAlignment.center(默认)CrossAxisAlignment.end
image.pngimage.pngimage.png
CrossAxisAlignment.stretchCrossAxisAlignment.baseline备注
image.pngimage.png设置 baseline 时,必须配合 textBaseline 进行设置。

Flex(弹性布局)

上面 2 个常用的聊完了,有人可能会问为啥要提到 Flex ?这里我们就需要看看源码了,跟着我一起来。

Column 源码

image.png
到这里可以看到 4918Column 就是继承自 Flex ,然后 4942 行指定了竖直方向 他就是 Column 了,那么 Row 会不会也是如此呢?一起看看吧

Row 源码

image.png
到这里我们可以看到和 Column 一样也是继承自 Flex ,然后指定了方向是横向排列。

Flex 源码

既然到这了,我们就看看 Flex 的源码吧,暂时不想看的,直接跳过即可,知道了初步的源码,以后了点进去随时看即可。
image.png
这里我们可以看到 4339 行,Flex 就是继承自 MultiChildRenderObjectWidget ,然后其他一大堆属性我们基本上面都分析过了。
image.png
最后在看看核心代码,通过 createRenderObject 方法创建了一个 RenderFlex 对象返回,然后在 updateRenderObject 方法中通过 .. 连级操作,重新对属性赋值。

到这里就完了,有兴趣可以继续深入看看哦 最后深夜更文不易,如有帮助请点赞支持哦

源码仓库

基于 Flutter 🔥 最新版本

参考链接

关注专栏

  • 此文章已收录到下面👇 的专栏,可以直接关注
  • 更多文章继续阅读|系列文章持续更新

👏 欢迎点赞➕收藏➕关注,有任何问题随时在下面👇评论,我会第一时间回复哦

文章分类
Android
文章标签