(两百六十三)Flutter - 学习处理边界约束 (Box constraints) 的问题

https://flutter.cn/docs/development/ui/layout/box-constraints

处理边界约束 (Box constraints) 的问题

Flutter 中的 widget 由在其底层的 RenderBox 对象渲染而成。渲染框由其父级 widget 给出约束,并根据这些约束调整自身尺寸大小。约束是由最小宽度、最大宽度、最小高度、最大高度四个方面构成;尺寸大小则由特定的宽度和高度两个方面构成。

一般来说,从如何处理约束的角度来看,有以下三种类型的渲染框:

对于一些诸如 Container 的 widget,其尺寸会因构造方法的参数而异,就 Container 来说,它默认是尽可能大的,而一旦给它一个特定的宽度,那么它就会遵照这个特定的宽度来调整自身尺寸。

其它一些像 Row and Column (flex boxes)这样的 widget ,其尺寸会因给定的约束而异,具体细节见后文 “Flex” 部分;

约束有时是”紧密的”,这意味着这些约束严格地限定了渲染框在定夺自身尺寸方面的空间(例如:当约束的最小宽度和最大宽度相同时,这种情况下,我们称这个约束有紧密宽度),这方面的主要例子是 App Widget,它是 RenderView 类里面的一个 widget: 由应用程序的 build 函数返回的子 widget 渲染框被指定了一个约束,该约束强制 App Widget 精确填充应用程序的内容区域(通常是整个屏幕)。 Flutter 中的许多渲染框,特别是那些只包含单个 widget 的渲染框,都会将自身的约束传递给他们的子级 widget。这意味着如果你在应用程序渲染树的根部嵌套了一些渲染框,这些框将会在受到约束的影响下相互适应彼此。

有些渲染框放松了约束,即:约束中只有最大宽度,最大高度,但没有最小宽度,最小高度,例如 Center

 

无边界约束

在某些情况下,传递给框的约束是 无边界 的或无限的。这意味着约束的最大宽度或最大高度为double.INFINITY

当传递无边界约束给类型为尽可能大的框时会失效,在 debug 模式下,则会抛出异常,该异常信息会把你引导到本页面。

渲染框具有无边界约束的最常见情况是:当其被置于 flex boxes (RowColumn)内以及 可滚动区域(ListView 和其它 ScrollView 的子类)内时。

特别是 ListView 会试图扩展以适应其交叉方向可用空间 (比如说,如果它是一个垂直滚动块,它将试图扩充到与其父 widget 一样宽)。如果让垂直滚动的 ListView 嵌套在水平滚动的 ListView 内,那么被嵌套在里面的垂直滚动的 ListView 将会试图尽可能宽,直到无限宽,因为将其嵌套的是一个水平滚动的ListView,它可以在水平方向上一直滚动。

 

Flex

Flex 框本身(RowColumn)的行为会有所不同,这取决于其在给定方向上是处于有边界约束还是无边界约束。

在有边界约束条件下,它们在给定方向上会尽可能大。

在无边界约束条件下,它们试图让其子 widget 自适应这个给定的方向。在这种情况下,不能将子 widget 的flex属性设置为 0(默认值)以外的任何值。这意味着在 widget 库中,当一个 flex 框嵌套在另外一个 flex 框或者嵌套在可滚动区域内时,不能使用 Expanded。如果这样做了,就会收到异常,该异常信息会把你引导到本页面。

交叉 方向上,如 Column(垂直的 flex)的宽度和 Row(水平的 flex)的高度,它们必将不能是无界的,否则它们将无法合理地对齐它们的子 widget。

 

之前用到flex是设定各个Row或者Column的各个widget的weight

https://blog.csdn.net/sinat_20059415/article/details/105800739

也许你想要一个 widget 占用的空间是兄弟项的两倍。为了达到这个效果,可以使用 Expanded widget 的 flex 属性,这是一个用来确定 widget 的弹性系数的整数。默认的弹性系数为 1。以下代码将中间图像的弹性系数设置为 2:

content_copy

    Row(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Expanded(
          child: Image.asset('images/pic1.jpg'),
        ),
        Expanded(
          flex: 2,
          child: Image.asset('images/pic2.jpg'),
        ),
        Expanded(
          child: Image.asset('images/pic3.jpg'),
        ),
      ],
    );

 

Understanding constraints

https://flutter.cn/docs/development/ui/layout/constraints

When someone learning Flutter asks you why some widget with width:100 isn’t 100 pixels wide, the default answer is to tell them to put that widget inside of a Center, right?

Don’t do that.

If you do, they’ll come back again and again, asking why some FittedBox isn’t working, why that Column is overflowing, or what IntrinsicWidth is supposed to be doing.

Instead, first tell them that Flutter layout is very different from HTML layout (which is probably where they’re coming from), and then make them memorize the following rule:

Constraints go down. Sizes go up. Parent sets position.

Flutter layout can’t really be understood without knowing this rule, so Flutter developers should learn it early on.

In more detail:

  • A widget gets its own constraints from its parent. A constraint is just a set of 4 doubles: a minimum and maximum width, and a minimum and maximum height.
  • Then the widget goes through its own list of children. One by one, the widget tells its children what their constraints are (which can be different for each child), and then asks each child what size it wants to be.
  • Then, the widget positions its children (horizontally in the x axis, and vertically in the y axis), one by one.
  • And, finally, the widget tells its parent about its own size (within the original constraints, of course).

For example, if a composed widget contains a column with some padding, and wants to lay out its two children as follows:

 

The negotiation goes something like this:

Widget: “Hey parent, what are my constraints?”

Parent: “You must be from 80 to 300 pixels wide, and 30 to 85 tall.”

Widget: “Hmmm, since I want to have 5 pixels of padding, then my children can have at most 290 pixels of width and 75 pixels of height.”

Widget: “Hey first child, You must be from 0 to 290 pixels wide, and 0 to 75 tall.”

First child: “OK, then I wish to be 290 pixels wide, and 20 pixels tall.”

Widget: “Hmmm, since I want to put my second child below the first one, this leaves only 55 pixels of height for my second child.”

Widget: “Hey second child, You must be from 0 to 290 wide, and 0 to 55 tall.”

Second child: “OK, I wish to be 140 pixels wide, and 30 pixels tall.”

Widget: “Very well. My first child has position x: 5 and y: 5, and my second child has x: 80 and y: 25.”

Widget: “Hey parent, I’ve decided that my size is going to be 300 pixels wide, and 60 pixels tall.”

Limitations

As a result of the layout rule mentioned above, Flutter’s layout engine has a few important limitations:

  • A widget can decide its own size only within the constraints given to it by its parent. This means a widget usually can’t have any size it wants.

  • A widget can’t know and doesn’t decide its own position in the screen, since it’s the widget’s parent who decides the position of the widget.

  • Since the parent’s size and position, in its turn, also depends on its own parent, it’s impossible to precisely define the size and position of any widget without taking into consideration the tree as a whole.

 

总结

简单来说各个widget都有对应的宽和高的限制,若无限制,则不能进行简单的分块操作,比如expanded,这种情况下子widget会自适应布局,从代码角度而言就是分块操作无法得知具体widget的高宽,以至于无法准确绘制。

另外学习下flutter布局的流程

  • A widget gets its own constraints from its parent. A constraint is just a set of 4 doubles: a minimum and maximum width, and a minimum and maximum height.
  • Then the widget goes through its own list of children. One by one, the widget tells its children what their constraints are (which can be different for each child), and then asks each child what size it wants to be.
  • Then, the widget positions its children (horizontally in the x axis, and vertically in the y axis), one by one.
  • And, finally, the widget tells its parent about its own size (within the original constraints, of course).

和要领

Constraints go down. Sizes go up. Parent sets position.

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章