https://flutter.cn/docs/development/ui/layout/constraints
Flutter 的布局方式与 HTML 的布局差异相当大 规则:
首先,上层 widget 向下层 widget 传递约束条件;
然后,下层 widget 向上层 widget 传递大小信息。
最后,上层 widget 决定下层 widget 的位置。
如果我们在开发时无法熟练运用这条规则,在布局时就不能完全理解其原理,所以越早掌握这条规则越好!
更多细节:
-
Widget 会通过它的 父级 获得自身的约束。约束实际上就是 4 个浮点类型的集合:最大/最小宽度,以及最大/最小高度。----------------------->>>这就是约束的全部
-
然后,这个 widget 将会逐个遍历它的 children 列表。向子级传递 约束(子级之间的约束可能会有所不同),然后询问它的每一个子级需要用于布局的大小。
-
然后,这个 widget 就会对它子级的 children 逐个进行布局。(水平方向是
x
轴,竖直是y
轴) -
最后,widget 将会把它的大小信息向上传递至父 widget(包括其原始约束条件)
限制
正如上述所介绍的布局规则中所说的那样, Flutter 的布局引擎有一些重要限制:
-
一个 widget 仅在其父级给其约束的情况下才能决定自身的大小。这意味着 widget 通常情况下 不能任意获得其想要的大小。
-
一个 widget 无法知道,也不需要决定其在屏幕中的位置。因为它的位置是由其父级决定的。
-
当轮到父级决定其大小和位置的时候,同样的也取决于它自身的父级。所以,在不考虑整棵树的情况下,几乎不可能精确定义任何 widget 的大小和位置。
https://flutter.cn/docs/development/ui/layout/box-constraints
Flutter 中的 widget 由在其底层的 RenderBox
对象渲染而成。渲染框由其父级 widget 给出约束,并根据这些约束调整自身尺寸大小。约束是由最小宽度、最大宽度、最小高度、最大高度四个方面构成;尺寸大小则由特定的宽度和高度两个方面构成。
1. 一般来说,从如何处理约束的角度来看,有以下三种类型的渲染框:
约束有时是”紧密的”,这意味着这些约束严格地限定了渲染框在定夺自身尺寸方面的空间(例如:当约束的最小宽度和最大宽度相同时,这种情况下,我们称这个约束有紧密宽度),这方面的主要例子是 App Widget,它是 RenderView
类里面的一个 widget: 由应用程序的 build
函数返回的子 widget 渲染框被指定了一个约束,该约束强制 App Widget 精确填充应用程序的内容区域(通常是整个屏幕)。 Flutter 中的许多渲染框,特别是那些只包含单个 widget 的渲染框,都会将自身的约束传递给他们的子级 widget。这意味着如果你在应用程序渲染树的根部嵌套了一些渲染框,这些框将会在受到约束的影响下相互适应彼此
注释:::指, 父widget可以强制约束子widget的大小
无边界约束 Unbounded constraints
在某些情况下,传递给框的约束是 无边界 的或无限的。这意味着约束的最大宽度或最大高度为double.INFINITY
。
当传递无边界约束给类型为尽可能大的框时会失效,在 debug 模式下,则会抛出异常,该异常信息会把你引导到本页面。
渲染框具有无边界约束的最常见情况是:当其被置于 flex boxes (Row
和 Column
)内以及 可滚动区域(ListView
和其它 ScrollView
的子类)内时。
特别是 ListView
会试图扩展以适应其交叉方向可用空间 (比如说,如果它是一个垂直滚动块,它将试图扩充到与其父 widget 一样宽)。如果让垂直滚动的 ListView
嵌套在水平滚动的 ListView
内,那么被嵌套在里面的垂直滚动的 ListView
将会试图尽可能宽,直到无限宽,因为将其嵌套的是一个水平滚动的ListView
,它可以在水平方向上一直滚动。
Flex (弹性,理解成权重,或者刚好内容大小)
Flex 框本身(Row
和 Column
)的行为会有所不同,这取决于其在给定方向上是处于有边界约束还是无边界约束。
在有边界约束条件下,它们在给定方向上会尽可能大。
在无边界约束条件下,它们试图让其子 widget 自适应这个给定的方向。在这种情况下,不能将子 widget 的flex
属性设置为 0(默认值)以外的任何值。这意味着在 widget 库中,当一个 flex 框嵌套在另外一个 flex 框或者嵌套在可滚动区域内时,不能使用 Expanded
。如果这样做了,就会收到异常,该异常信息会把你引导到本页面。
在 交叉 方向上,如 Column
(垂直的 flex)的宽度和 Row
(水平的 flex)的高度,它们必将不能是无界的,否则它们将无法合理地对齐它们的子 widget。