布局约束
Flutter 中有两种布局模型:
- 基于 RenderBox 的盒模型布局。
- 基于 Sliver ( RenderSliver ) 按需加载列表布局。
大致布局流程如下:
- 上层组件向下层组件传递约束(constraints)条件。
- 下层组件确定自己的大小,然后告诉上层组件。注意下层组件的大小必须符合父组件的约束。
- 上层组件确定下层组件相对于自身的偏移和确定自身的大小(大多数情况下会根据子组件的大小来确定自身的大小)。
因为任何时候子组件都必须先遵守父组件的约束
盒模型布局组件有两个特点:
- 组件对应的渲染对象都继承自 RenderBox 类。在本书后面文章中如果提到某个组件是 RenderBox,则指它是基于盒模型布局的,而不是说组件是 RenderBox 类的实例。
- 在布局过程中父级传递给子级的约束信息由 BoxConstraints 描述。
BoxConstraints (父->子)的约束信息
1 | const BoxConstraints({ |
BoxConstraints.tight(Size size),它可以生成固定宽高的限制;
BoxConstraints.expand()可以生成一个尽可能大的用以填充另一个容器的BoxConstraints;
ConstrainedBox
通过约束限制子组件大小的组件
1 | // 临时定义一个 |
1 | Widget testConstrainedBox() { |
效果
虽然自组件设置的高是20, 但是父组件约束了最小为80, 所以高度是80
SizedBox
SizedBox只是ConstrainedBox的一个定制,
1 | SizedBox(width: 80.0, height: 80.0, child: yellowBox) |
其实ConstrainedBox
和SizedBox
都是通过RenderConstrainedBox
来渲染的;
多层约束
如果使用多层ConstrainedBox父组件 会是什么情况呢?
1 | // 外小 内大 |
因为约束条件是用来约束子组件的
- 一层约束时很好理解, 即:
maxSize >= 最终大小 && 最终大小 >= minSize
- 那两层也不难理解, 只要两层约束条件都满足即可:
1
2
3
4
5// maxSize1 >= 最终大小 && 最终大小 >= minSize1
// &&
// maxSize2 >= 最终大小 && 最终大小 >= minSize2
// 整理即可得出
// min(maxSize1, maxSize2) >= 最终大小 >= max(minSize1, minSize2)
UnconstrainedBox
虽然任何时候子组件都必须遵守其父组件的约束,但前提条件是它们必须是父子关系,
1 | ConstrainedBox( // 曾祖父组件 |
任何时候子组件都必须遵守其父组件的约束
需要注意,UnconstrainedBox 虽然在其子组件布局时可以取消约束(子组件可以为无限大),但是 UnconstrainedBox 自身是受其父组件约束的,所以当 UnconstrainedBox 随着其子组件变大后,如果UnconstrainedBox 的大小超过它父组件约束时,也会导致溢出报错!
其他约束类
还有一些其他的尺寸限制类容器
AspectRatio
它可以指定子组件的长宽比、LimitedBox
用于指定最大宽高、FractionallySizedBox
可以根据父容器宽高的百分比来设置子组件宽高等