flutter 系列之:UI layout 简介
简介
对于一个前端框架来说,除了各个组件之外,最重要的就是将这些组件进行连接的布局了。布局的英文名叫做 layout,就是用来描述如何将组件进行摆放的一个约束。
在 flutter 中,基本上所有的对象都是 widget,对于 layout 来说也不例外。也就是说在 flutter 中 layout 也是用代码来完成的,这和其他的用配置文件来描述 layout 的语言有所不同。
你可以把 layout 看做是一种看不见的 widget,这些看不见的 widget 是用来作用在可见的 widget 对象上,给他们实施一些限制。
flutter 中 layout 的分类
flutter 中的 layout widget 有很多,他们大概可以分为三类,分别是只包含一个 child 的 layout widget,可以包含多个 child 的 layout widget 和可滑动的 Sliver widgets。
这三种 layout 也有很多种具体的实现,对于 Single-child layout widgets 来说,包含下面这些 widgets:
Align -- 用来对其包含在其中的组件进行对其操作。
AspectRatio -- 对其中的组件进行比例缩放。
Baseline -- 通过使用子组件的 baseline 来进行定位。
Center -- 自组件位于中间。
ConstrainedBox -- 类似于 IOS 中的 constrain,表示子组件的限制条件。
Container -- 一个常用的 widget,可以用来包含多个其他的 widget。
CustomSingleChildLayout -- 将其单个子项的布局推迟。
Expanded -- 将 Row, Column 或者 Flex 的 child 进行扩展。
FittedBox -- 根据 fit 来缩放和定位其 child。
FractionallySizedBox -- 将 child 按照总可用空间进行调整。
IntrinsicHeight -- 一个将其 child 调整为 child 固有高度的小部件。
IntrinsicWidth -- 一个将其 child 调整为 child 固有宽度的小部件。
LimitedBox -- 限制一个 box 的 size。
Offstage -- 将 child 放入 render tree 中,但是却并不触发任何重绘。
OverflowBox -- 允许 child 覆盖父组件的限制。
Padding -- 为 child 提供 padding。
SizedBox -- 给定 size 的 box。
SizedOverflowBox -- 可以覆盖父组件限制的 box。
Transform -- 子组件可以变换。
以上是包含单个 child 的 layout 组件,下面是可以包含多个 child 的 layout 组件:
Column -- 表示一列 child。
CustomMultiChildLayout -- 使用代理来定位和缩放子组件。
Flow -- 流式布局。
GridView -- 网格布局。
IndexedStack -- 从一系列的 child 中展示其中的一个 child。
LayoutBuilder -- 可以依赖父组件大小的 widget tree。
ListBody -- 根据给定的 axis 来布局 child。
ListView -- 可滚动的列表。
Row -- 表示一行 child。
Stack -- 栈式布局的组件。
Table -- 表格形式的组件。
Wrap -- 可以对子 child 进行动态调整的 widget。
可滑动的 Sliver widgets 有下面几种:
CupertinoSliverNavigationBar -- 是一种 IOS 风格的导航 bar。
CustomScrollView -- 可以自定义 scroll 效果的 ScrollView。
SliverAppBar -- material 风格的 app bar,其中包含了 CustomScrollView。
SliverChildBuilderDelegate -- 使用 builder callback 为 slivers 提供 child 的委托。
SliverChildListDelegate -- 使用 list 来为 livers 提供 child 的委托。
SliverFixedExtentList -- 固定 axis extent 的 sliver。
SliverGrid -- child 是二维分布的 sliver。
SliverList -- child 是线性布局的 sliver。
SliverPadding -- 提供 padding 的 sliver。
SliverPersistentHeader -- 可变 size 的 sliver。
SliverToBoxAdapter -- 包含单个 box widget 的 Sliver。
常用 layout 举例
上面我们列出了所有的 flutter layout,他们几乎满足了我们在程序中会用到的所有 layout 需求,这里我们以两个最基本和最常用的 layout:Row 和 Column 为例,来详细讲解 layout 的使用。
Row 和 Column 都属于上面讲到的多个 child 的 layout widget,它里面可以包含多个其他的 widget 组件。
先看一下 Row 和 column 的定义。
可以看到 Row 和 Column 都继承自 Flex,并且他们的构造方法都是调用了 Flex 的构造方法,两者的区别就在于 direction 不同,Row 的 direction 是 Axis.horizontal,而 Column 的 direction 是 Axis.vertical。
那么什么是 Flex 呢?
Flex 是一个 widget,在 Flex 中的子组件会按照某一个指定的方向进行展示。这个方向是可以控制的,比如横向或者竖向,如果你已经提前知道了主轴的方向,那么可以使用 Row 或者 Column 来替代 Flex,因为这样更加简洁。
在 Flex 中,如果想要 child 在某个方向填满可用空间,则可以将该 child 包装在 Expanded 中。
要注意的是,Flex 是不可滚动的,如果 Flex 中的 child 太多,超出了 Flex 中的可用空间,那么 Flex 将会报错,所以如果你需要展示很多 child 的情况下,可以考虑使用可滚动的组件,比如 ListView。
如果你只有一个 child,那么就没有必要使用 Flex 或者 Row 和 Column 了,可以考虑使用 Align 或者 Center 来对 child 进行定位。
在 Flex 中有几个非常重要的参数,比如 mainAxisAlignment 表示的是子组件沿主轴方向的排列规则,mainAxisSize 表示的是主轴的 size 大小,crossAxisAlignment 表示的是和主轴垂直轴的子组件排列规则。当然还有它最最重要的 children 属性,children 是一个 Widget 的 list 列表,用来存储要展示的子组件。
以 Row 为例,我们创建一个简单的 RowWidget:
这里我们返回了一个 Row 对象,设置了 textDirection 和 children 属性。
children 里面是自定义的 YellowBox:
YellowBox 是一个长和宽都是 50 的正方形。我们这里使用了 BoxDecoration 对其上色。
最后将 RowWidget 放到 Scaffold 的 body 里面,如下所示:
我们可以看到下面的图像:
大家可以看到 YellowBox 是紧贴在一起的,如果我们想要均匀分别该如何做呢?
我们可以在 Row 中添加一个属性叫做 mainAxisAlignment,取值如下:
重新运行,生成的图像如下:
上面我们还提到了一个 Expanded 组件,可以用来填充剩余的可用空间,我们把最后一个 YellowBox 用 Expanded 围起来,如下所示:
生成的图像如下:
可以看到最后一个 Box 填充到了整个 Row 剩余的空间。
大家要注意,这时候 mainAxisAlignment 是没有效果的。
如果观察 Expanded 的构造函数,可以看到 Expanded 还有一个 flex 属性:
flex 属性表示的是 flex factor,默认值是 1,还是上面的例子,我们将 flex 调整为 2,看看效果:
运行的结果和 flex=1 是一样的,为什么呢?
事实上这个 flex 表示的是相对于其他 Expanded 的组件所占用的空间比例。我们可以讲所有的子组件都用 Expanded 进行扩充,然后再看看效果:
运行结果如下:
可以看到最后一个 child 占用的空间是前面两个的两倍。
如果我们想要在 YellowBox 中间添加空格怎么办呢?有两种方法。
第一种方法是使用 SizedBox,如下:
SizedBox 里面可以包含子 child,从而重新设置子 child 的长度和高度。如果不包含子 child 则会生成一个空格。
还有一种方式是使用 Spacer,如下所示:
生成的图像如下:
Spacer 和 SizedBox 都可以生成空白,不同的是 Spacer 可以和 flex 一起使用,而 SizedBox 必须固定 size 大小。
总结
以上就是 fluter 中 layout 和的分类和基本 layout Row 和 Column 的使用情况了。
本文的例子:https://github.com/ddean2009/learn-flutter.git
更多内容请参考 http://www.flydean.com/07-flutter-ui-layout-overview/
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
版权声明: 本文为 InfoQ 作者【程序那些事】的原创文章。
原文链接:【http://xie.infoq.cn/article/bd5942427e9dc1e1b8aeab639】。文章转载请联系作者。
评论