阅读 759

【Flutter 基础】视图布局(一)基本概念

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

注:本文从个人公众号(岛前屿端)中迁移重新发布

Flutter 是谷歌的移动 UI 框架,可以从单个代码库快速的为移动端(iOS & Android)、Web、桌面端、嵌入式设备上构建高质量的原生用户界面和应用程序。


在布局 Widget 中 Row、Column、ListBody、ListView、Wrap、Flow 都是用于整个页面布局的 Widget,因为这些都支持存在多个子元素,较 html 语言来说,它严格规定了哪些 Widget 是可以存在多个子元素哪些 Widget 是只能存在单个子元素。

在 Flutter 的实际使用中 Row、Column、ListView 这三者都是使用频率较高的布局 Widget 。

在了解布局之前还要先了解一些其他的概念。

“轴”的概念

Flutter 中 Row、Column 与其他语言相较不同的是使用了 Axis “轴” 的概念。

这里 Row、Column 的实现也继承了 Flex ,在一定程度上还是与 CSS flex 有点相似。

image.png
(Row、Column 继承关系)

“轴”应该怎么理解?

按照字面意思 Row 我们都会认为是行, Column 我们会认为是列,在这点上没有异议。但在这里加入了 Main Axis(主轴)、Cross Axis(交叉轴) 的概念

这是什么意思呢?就是说当前 Widget 渲染如果是横向的,那么它的主轴就是横向的,则交叉轴就是纵向的。渲染 Widget 渲染如果是纵向的,那么它的主轴就是纵向的,则交叉轴就是横向的。

咋一看这个描述的时候你可能一脸 ???

image.png

没关系那我们用传统一点的 xy 来转换一下:

渲染 Row 是行,它是横向的,那么它的主轴x 轴,交叉轴y 轴。

渲染 Column 是列,它是纵向的,那么它的主轴y 轴,交叉轴x 轴。

这样来说明的话应该可以理解了吧?

什么?你说还不明白?我的天呐,怎么会有这样的人?既然这样的话那就别怪我放大招了!来人呐!给我上图!

image.png
(Row、Column 轴关系)

这里虽然 Cross Axis 是翻译为 “交叉轴” ,但我个人更喜欢称之为 “副轴” ,因为这样在理解上会相对清晰很多。当然,这是个人习惯问题,各位少侠亦可按翻译所理解。

属性构成

在理解完后 “轴” 的概念后,我们就可以看一看它的属性构成

不多逼逼,直接上源码了!

image.png
(Row 属性构成)

image.png
(Column 属性构成)

在源码中可以看到 Row、Column 拥有以上属性,这些属性均继承自 Flex 。这些属性大多为 enum 枚举类型,也就是说只要通过 “.” 调用获取有限的不可更改的数据列表的值就 Ok,免去了输入字符串可能导致的字符不匹配 or 魔法字符串的问题。

// 主轴的对齐方式
MainAxisAlignment mainAxisAlignment
// 交叉(副)轴的对齐方式
CrossAxisAlignment crossAxisAlignment
// 主轴方向的大小,即占有空间
MainAxisSize mainAxisSize
// 垂直方向 - 默认向下
VerticalDirection verticalDirection
// 文字方向 - 一般默认
TextDirection textDirection
// 文字基线
TextBaseline textBaseline
// 子元素列表,类型为 Widget
List<Widget> children
复制代码

布局属性

简单了解了基本属性之后,那么就来说说主要影响布局结构的 3 个属性:

  • mainAxisAlignment
  • crossAxisAlignment
  • mainAxisSize

mainAxisAlignment

mainAxisAlignment 是主轴的对齐方式,其中 Row 的主轴为 x 轴,Column 的主轴为 y 轴。

在我探索 mainAxisAlignment 对齐方式的最终渲染结果的时候,我发现其实可以将它分为两种对齐方式会更好理解。一种是轴线对齐方式,一种是空间分配对齐方式

轴线对齐方式就是以主轴线为基础进行的平移对齐

空间分配对齐方式就是以主轴线为基础对轴上空间进行分配的对齐方式。

轴线对齐方式

  • start 默认值,即 Row 主轴上左对齐,Column 主轴上顶部对齐
  • end 即 Row 主轴上右对齐,Column 主轴上底部对齐
  • center 即 Row 主轴上水平居中对齐,Column 主轴上垂直居中对齐

image.png
(轴线对齐方式)

空间分配对齐方式

  • spaceBetween 左右两极对齐,剩余元素以相同间隔平均分配剩余空间
  • spaceAround 每个元素以相同的左右间隔平均分配剩余空间
  • spaceEvenly 所有元素以相同的间隔平均分配剩余空间

image.png
(空间分配对齐方式)

crossAxisAlignment

crossAxisAlignment 是交叉轴的对齐方式,我称之为副轴,其中 Row 的交叉(副)轴为 y 轴,Column 的交叉(副)轴为 x 轴。

  • start 即 Row 交叉轴的顶部对齐,Column 交叉轴的左对齐
  • end 即 Row 交叉轴的底部对齐,Column 交叉轴的右对齐
  • center 默认值,即 Row 交叉轴的垂直居中对齐,Column 交叉轴的水平居中对齐
  • stretch 将 Row 子元素拉伸交叉轴高度相同,Column 子元素拉伸交叉轴宽度相同
  • baseline 需要与 TextBaseline 配合使用

不出意外,在交叉(副)轴上 start、end、center 的渲染表现还是符合预期的。

image.png
(交叉轴的对齐方式)

stretch

stretch 就是以交叉轴为基础,将交叉轴上的子元素拉伸至与交叉轴所占空间相同,但又不影响主轴方向的空间

以上就是影响主轴、交叉(副)轴最终渲染视图时的主要属性了。

mainAxisSize

mainAxisSize 也是比较简单的属性,从命名上来理解看就可以知道大概结果。主轴大小,意思就是这个属性控制着在 Row、Column 主轴方向上的大小

它有两个值 max、min,默认值为 max。max 就是在主轴上大小为 100%,而 min 就是子元素所需最小空间,此时主轴上的对齐方式就看不出效果了。

verticalDirection

接下来就要说说会影响垂直方向行为的属性 verticalDirection,在源码中对于 verticalDirection 部分的说明

(图丢了,找时间补图)

意思就是说 verticalDirection 属性会影响垂直方向的渲染行为,也就是会改变垂直方向的对齐方式。

verticalDirection 垂直的排列方向,它有两个值 up、down,默认值为 down。

用代码作为参考来看:

image.png
(verticalDirection 影响行为)

它只影响垂直方向的行为,对水平方向并无影响,即是影响 Row 的交叉轴Column 的主轴

textDirection

textDirection 这个就不用详细说明了,就是文字书写方向。

textBaseline

关于 textBaseline 属性,很抱歉!尝试了多种与文字设定的方式配合后,依然没有在最后渲染的视图上表现出来 alphabetic、ideographic 两个值的差异。

案例实现

了解完了基本信息后还是需要动下小手的,那我们就来实现一下 Flutter 中文网中给出的例子:【在Flutter中构建布局】

image.png

可以看出它将设计图拆分为基本的元素,它分为4部分:一张图片,标题 + 按钮,功能按钮组以及文本块。

那我们就要考虑找出它最大的包裹元素,所以这里是 1 列 4 行。因为是从上到下所以这里用 Column 先确定列,再使用 4 个子元素实现行内容。

image.png

因为 Flutter 中文网已给出代码,所以这里就不详细说明实现步骤。具体代码可以参考:【在Flutter中构建布局】

问题

假设在不考虑功能的情况下使用 Row 和 Column 来完成如下布局,你会如何考虑和设计?

期待你的思考结果和动手结果

image.png


总结

Flutter 布局机制的核心就是 widget。在 Flutter 中,几乎所有东西都是一个 widget - 甚至布局模型都是 widget。其实在使用起来和 html 的标签逻辑还是大部分相似的,只不过这里将这些 widget 设计得更细,每个 widget 都负责固定的渲染结果或行为模式。只要能够理解这些 widget 那么视图布局还是比较容易实现的。

最后

  • 对于布局来说,难点不在于多复杂,而是在于你如何去理解拆分它。
  • 多思考学一种新语言和你所学过的语言有那些相似或者不同之处,对于相似之处可以快速理解,不同之处可以针对性理解。

配合文章一同食用的代码已同步更新到 Github 地址:github.com/linxsbox/my…

前置阅读:【Flutter 基础】 视图布局-前言

文章分类
前端
文章标签