flutter:掌握布局约束Constraint

Understanding constraints

掌握constraints

前言:文章内容比较多,尤其是后面的29例子,通过各个widget的组合体现constraints 的特性,非专业翻译,有错误之处麻烦留言指出,谢谢~。

原文地址【英文】【翻墙】:https://flutter.dev/docs/development/ui/layout/constraints

this GitHub repo

在这里插入图片描述
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?
当某个flutter的学习者问你“为什么一些widget,写了width:100 ,但是并没有显示100宽度”,一般情况下,你可能会告诉他们,“把那widget放在Center 中。”

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.
如果这么说了,他们就会反反复复的问:“为什么一些FittedBox不能生效?为什么Column超出了边界?或者,IntrinsicWidth该怎么设置?”

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:
所以,一开始就应该告诉他们Flutter布局是和HTML布局十分不相同的(这也是Flutter的诞生理由,详情可看What is Flutter),并且让他们记住下面的规则

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.
如果不知道上面的规则,Flutter的布局是很难真正掌握的,所以Flutter开发者应该尽早学会这条规则

In more detail:
详细的讲:

1、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.

1、一个widget的constraints 来自于他的父容器widget。一个constraints 仅仅设置了四个“双精浮点数”: minimum 和 maximum 宽, minimum 和 maximum 高。

2、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.

2、然后,widget会一个接着一个的遍历他的子widget,传递他的子widget们对应的constraints(每个子widget拿到的constraints可能是不通的),并且让他的子widget设置自己想要的大小

3、Then, the widget positions its children (horizontally in the x axis, and vertically in the y axis), one by one.

3、然后,widget会一个接着一个设置他的子widget的位置(x轴水平布局,y轴垂直布局)

4、And, finally, the widget tells its parent about its own size (within the original constraints, of course).

4、最后,widget会把自己的大小向上传递给自己的父容器(当然,是通过一开始从父容器中拿到的constraints来传递的)

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

举个栗子,如下所示,一个widget元件以列的形式包含了两个widget,并且设置了padding:

在这里插入图片描述
The negotiation goes something like this:
(布局的)协商过程会大概这样:

Widget: “Hey parent, what are my constraints?”
Widget: “嘿 父容器, 我的constraints是什么?”

Parent: “You must be from 80 to 300 pixels wide, and 30 to 85 tall.”
Parent: “你必须从 80 到 300 像素 宽度(译者注:从图文推断,感觉这应该是说“0到300像素的宽”), 同时 30 到 85的(像素)高。”

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: “哈,因为我想要5像素的padding,所以我的子widget只能有290像素的宽和75像素的高咯”

Widget: “Hey first child, You must be from 0 to 290 pixels wide, and 0 to 75 tall.”
Widget: “嘿 first child, 你的布局范围必须限制 在0到290像素宽度 和 0到75的像素高”

First child: “OK, then I wish to be 290 pixels wide, and 20 pixels tall.”
First child: “OK, 我将会要290像素宽度和20的像素高。”

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: “哈,因为我想要把我的second child放到first child下面,现在只留下55像素高度给我的second child。”

Widget: “Hey second child, You must be from 0 to 290 wide, and 0 to 55 tall.”
Widget: “嘿,second child,你的展示范围必须是在 0 到 290 宽度, 0 到 55 高度。”

Second child: “OK, I wish to be 140 pixels wide, and 30 pixels tall.”
Second child: “OK, 我想要的是140像素宽,30像素高”

Widget: “Very well. My first child has position x: 5 and y: 5, and my second child has x: 80 and y: 25.”
Widget: “很好,我的 first child 的起始位置是x: 5 和 y: 5,然后我的second child 的起始位置是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.”

Widget: “嘿, 父容器, 我已经决定了,我的大小是300像素宽度,60像素高度。”

Limitations

限制条件

As a result of the layout rule mentioned above, Flutter’s layout engine has a few important limitations:
就之前就提到过的布局规则,flutter的布局egine 有下列的限制条件

1、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.

1、一个widget 只能在父容器widget给的 constraints 范围内 决定自己的大小。这意味着通常widget的大小不是想怎么决定都可以的。

2、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.
2、一个widget不能知道并且不能决定自己在屏幕上的位置,因为是他的父容器widget 决定他的位置。

3、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.
3、因为某个widget 的 “父容器widget”的大小和位置,是由“父容器widget”的父容器决定的,所以他在没有精确遍历整个布局树的情况下,是没有办法精确的确定任何一个widget的大小和位置。

4、If a child wants a different size from its parent and the parent doesn’t have enough information to align it, then the child’s size might be ignored. Be specific when defining alignment. 4、如果一个子widget想要设置的大小和父容器给的范围不同,并且父容器并没有足够的信息告诉子widget怎么对齐,子widget的大小可能会被忽略。因为精确的大小是需要依附明确的对齐方式的。

Examples

示例代码

29个示例的代码地址

Example 1

在这里插入图片描述

Container(color: Colors.red)

The screen is the parent of the Container, and it forces the Container to be exactly the same size as the screen.
屏幕就是Container的父容器,它强制 Container 的大小等同于屏幕大小

So the Container fills the screen and paints it red.
所以Container的填充了整个屏幕,并且绘制成红色

Example 2

在这里插入图片描述

Container(width: 100, height: 100, color: Colors.red)

The red Container wants to be 100 × 100, but it can’t, because the screen forces it to be exactly the same size as the screen.
这个红色Container想要100 × 100的大小,但是它不行,因为屏幕强制它的大小等同于屏幕大小了(译者:参考之前的限制条件,这里应该是对齐方式没有指明)。

So the Container fills the screen.
所以这个Container 填充了屏幕

Example 3

在这里插入图片描述

Center(
   child: Container(width: 100, height: 100, color: Colors.red)
)

The screen forces the Center to be exactly the same size as the screen, so the Center fills the screen.
屏幕强制 Center 的大小等同于屏幕大小,所以Center 填充了屏幕

The Center tells the Container that it can be any size it wants, but not bigger than the screen. Now the Container can indeed be 100 × 100.
Center 告诉 Container:它可以想要任何大小,但是不能超过屏幕。现在,Container的大小精确为100 × 100。

Example 4

在这里插入图片描述

Align(
   alignment: Alignment.bottomRight,
   child: Container(width: 100, height: 100, color: Colors.red),
)

This is different from the previous example in that it uses Align instead of Center.
不同于之前的例子,这里的对齐方式使用的是 Align 替代了 Center

Align also tells the Container that it can be any size it wants, but if there is empty space it won’t center the Container. Instead, it aligns the container to the bottom-right of the available space.

Align 告诉 Container:它可以想要任何大小,但是如果这里有任何空闲出来的空间,**Container*不会居中。而是,它会对齐到右下角

Example 5

在这里插入图片描述

Center(
   child: Container(
      color: Colors.red,
      width: double.infinity,
      height: double.infinity,
   )
)

The screen forces the Center to be exactly the same size as the screen, so the Center fills the screen.
屏幕强制 Center 的大小等同于屏幕大小,所以Center 填充了屏幕

The Center tells the Container that it can be any size it wants, but not bigger than the screen. The Container wants to be of infinite size, but since it can’t be bigger than the screen, it just fills the screen.
Center 告诉 Container:它可以想要任何大小,但是不能超过屏幕。现在,Container想要无限大,但是因为它不能超过屏幕大小,所以它仅仅就是填充屏幕。

Example 6

在这里插入图片描述

Center(child: Container(color: Colors.red))

The screen forces the Center to be exactly the same size as the screen, so the Center fills the screen.
屏幕强制了Center 的大小等同屏幕大小,所以Center 填充了屏幕。

The Center tells the Container that it can be any size it wants, but not bigger than the screen. Since the Container has no child and no fixed size, it decides it wants to be as big as possible, so it fills the whole screen.
Center告诉 Container:它可以想要任何大小,但是不能超过屏幕。因为Container没有子widget也没有设置固定大小,所以它就尽可能设置大小,因此他填充了整个屏幕。

But why does the Container decide that? Simply because that’s a design decision by those who created the Container widget. It could have been created differently, and you have to read the Container documentation to understand how it behaves, depending on the circumstances.

但是为什么Container 会这样决策呢?简单来讲,是由Container的创建设计策略的处理的,它可以有不同创建模式,你必须去阅读 Container documentation ,才能明白它的行为,整个取决于它的当前环境。

Example 7

在这里插入图片描述

Center(
   child: Container(
      color: Colors.red,
      child: Container(color: Colors.green, width: 30, height: 30),
   )
)

The screen forces the Center to be exactly the same size as the screen, so the Center fills the screen.
屏幕强制了Center 的大小等同屏幕大小,所以Center 填充了屏幕。

The Center tells the red Container that it can be any size it wants, but not bigger than the screen. Since the red Container has no size but has a child, it decides it wants to be the same size as its child.
Center 告诉 红色Container:它可以想要任何大小,但是不能超过屏幕。因为红色Container没有大小,但是有子widget,所以它决定
设置自己的大小和子widget一样。

The red Container tells its child that it can be any size it wants, but not bigger than the screen.
红色Container告诉它的子widget:你可以想要任何大小,但是不能超过屏幕。

The child is a green Container that wants to be 30 × 30. Given that the red Container sizes itself to the size of its child, it is also 30 × 30.
子widget是一个绿色的30x30大小的Container。所以就给了红色Container大小,红色Container决定自己的大小也一样是 30 × 30。
The red color isn’t visible because the green Container entirely covers the red Container.
这里红色是看不到的,因为绿色Container完全覆盖了红色 Container

Example 8

在这里插入图片描述

Center(
   child: Container(
     color: Colors.red,
     padding: const EdgeInsets.all(20.0),
     child: Container(color: Colors.green, width: 30, height: 30),
   )
)

The red Container sizes itself to its children’s size, but it takes its own padding into consideration. So it is also 30 × 30 plus padding. The red color is visible because of the padding, and the green Container has the same size as in the previous example.
红色的Container 大小是随着他的子widget的大小,但是它设置了自己的周边padding,所以它还有30x30之外的额外padding区间。这红色就因为padding显示出来了,绿色的Container有同上一个例子一样的大小。

Example 9

在这里插入图片描述

ConstrainedBox(
   constraints: BoxConstraints(
      minWidth: 70,
      minHeight: 70,
      maxWidth: 150,
      maxHeight: 150,
   ),
   child: Container(color: Colors.red, width: 10, height: 10),
)

You might guess that the Container has to be between 70 and 150 pixels, but you would be wrong. The ConstrainedBox only imposes additional constraints from those it receives from its parent.
你可能猜测 Container会有70到150像素的大小,但是你猜错了。这个ConstrainedBox是强推行了来自它的父容器widget的additional (外来的)constraints。

Here, the screen forces the ConstrainedBox to be exactly the same size as the screen, so it tells its child Container to also assume the size of the screen, thus ignoring its constraints parameter.
这里,屏幕强制了ConstrainedBox的大小等同于屏幕大小,所以它告诉它的子widget Container的大小也匹配屏幕大小,所以忽略了它的大小参数。

Example 10

在这里插入图片描述

Center(
   child: ConstrainedBox(
      constraints: BoxConstraints(
         minWidth: 70,
         minHeight: 70,
         maxWidth: 150,
         maxHeight: 150,
      ),
      child: Container(color: Colors.red, width: 10, height: 10),
   )
)

Now, Center allows ConstrainedBox to be any size up to the screen size. The ConstrainedBox imposes additional constraints from its constraints parameter onto its child.
现在, Center 允许了ConstrainedBox可以设置成不大于屏幕的任何大小。 ConstrainedBox 基于自己的constraint 强推了各式constraints 参数给子widget。

The Container must be between 70 and 150 pixels. It wants to have 10 pixels, so it ends up having 70 (the minimum).
Container 必须展示在70到150像素范围内,它自己是想要10像素大小,但是只能展示成70像素。(因为minimum参数)。

Example 11

在这里插入图片描述

Center(
  child: ConstrainedBox(
     constraints: BoxConstraints(
        minWidth: 70,
        minHeight: 70,
        maxWidth: 150,
        maxHeight: 150,
        ),
     child: Container(color: Colors.red, width: 1000, height: 1000),
  )
)

Center allows ConstrainedBox to be any size up to the screen size. The ConstrainedBox imposes additional constraints from its constraints parameter onto its child.
现在, Center 允许了ConstrainedBox可以设置成不大于屏幕的任何大小。 ConstrainedBox 基于自己的constraint 强推了各式constraints 参数给子widget。

The Container must be between 70 and 150 pixels. It wants to have 1000 pixels, so it ends up having 150 (the maximum).
Container 必须展示在70到150像素范围内,它自己是想要1000像素大小,但是只能展示成70像素。(因为maximum参数)。

Example 12

在这里插入图片描述

Center(
   child: ConstrainedBox(
      constraints: BoxConstraints(
         minWidth: 70,
         minHeight: 70,
         maxWidth: 150,
         maxHeight: 150,
      ),
      child: Container(color: Colors.red, width: 100, height: 100),
   )
)

Center allows ConstrainedBox to be any size up to the screen size. The ConstrainedBox imposes additional constraints from its constraints parameter onto its child.
现在, Center 允许了ConstrainedBox可以设置成不大于屏幕的任何大小。 ConstrainedBox 基于自己的constraint 强推了各式constraints 参数给子widget。

The Container must be between 70 and 150 pixels. It wants to have 100 pixels, and that’s the size it has, since that’s between 70 and 150.
Container 必须展示在70到150像素范围内,它自己是想要100像素大小,结果他确实以这个大小显示,因为100像素是在70~150范围呢。

Example 13

在这里插入图片描述

UnconstrainedBox(
   child: Container(color: Colors.red, width: 20, height: 50),
)

The screen forces the UnconstrainedBox to be exactly the same size as the screen. However, the UnconstrainedBox lets its child Container be any size it wants.
屏幕强制了 UnconstrainedBox的大小等同于屏幕大小。然而,UnconstrainedBox让它的子widget Container设置成任何想要的大小。

Example 14

在这里插入图片描述

UnconstrainedBox(
   child: Container(color: Colors.red, width: 4000, height: 50),
)

The screen forces the UnconstrainedBox to be exactly the same size as the screen, and UnconstrainedBox lets its child Container be any size it wants.
屏幕强制了 UnconstrainedBox的大小等同于屏幕大小。然而,UnconstrainedBox让它的子widget Container设置成任何想要的大小。

Unfortunately, in this case the Container is 4000 pixels wide and is too big to fit in the UnconstrainedBox, so the UnconstrainedBox displays the much dreaded “overflow warning”.
不幸的是,在这个例子里, Container是4000像素宽度,这太宽了,超过了UnconstrainedBox的适配。所以UnconstrainedBox 展示了极其可怕的 “overflow warning”(内容溢出警告)。

Example 15

在这里插入图片描述

OverflowBox(
   minWidth: 0.0,
   minHeight: 0.0,
   maxWidth: double.infinity,
   maxHeight: double.infinity,
   child: Container(color: Colors.red, width: 4000, height: 50),
);

The screen forces the OverflowBox to be exactly the same size as the screen, and OverflowBox lets its child Container be any size it wants.
屏幕强制了 OverflowBox的大小等同于屏幕大小。然而,OverflowBox让它的子widget Container设置成任何想要的大小。

OverflowBox is similar to UnconstrainedBox; the difference is that it won’t display any warnings if the child doesn’t fit the space.
OverflowBoxUnconstrainedBox很相似。不同之处是OverflowBox在子widget超出大小的时候,不会展示任何警告。

In this case, the Container has 4000 pixels of width, and is too big to fit in the OverflowBox, but the OverflowBox simply shows as much as it can, with no warnings given.
在这个例子里, Container是4000像素宽度,这太宽了,超过了OverflowBox的适配,但是OverflowBox只是简单的尽可能展示,不会给出警告。

Example 16

在这里插入图片描述

UnconstrainedBox(
   child: Container(
      color: Colors.red,
      width: double.infinity,
      height: 100,
   )
)

This won’t render anything, and you’ll see an error in the console.
这里不会绘制任何东西,而且你会在console中看到错误信息。

The UnconstrainedBox lets its child be any size it wants, however its child is a Container with infinite size.
UnconstrainedBox让它的子widget可以设置成任何大小,然而,它的子widget是一个无限大小的Container。

Flutter can’t render infinite sizes, so it throws an error with the following message: BoxConstraints forces an infinite width.
flutter不能绘制无限大小。所以抛出了错误信息:BoxConstraints forces an infinite width.

Example 17

在这里插入图片描述

UnconstrainedBox(
   child: LimitedBox(
      maxWidth: 100,
      child: Container(
         color: Colors.red,
         width: double.infinity,
         height: 100,
      )
   )
)

Here you won’t get an error anymore, because when the LimitedBox is given an infinite size by the UnconstrainedBox; it passes a maximum width of 100 down to its child.
这里,你不会再收到任何错误信息,因为当 LimitedBoxUnconstrainedBox之下给出无限大小,它会传出一个100down的maximum值。

If you swap the UnconstrainedBox for a Center widget, the LimitedBox won’t apply its limit anymore (since its limit is only applied when it gets infinite constraints), and the width of the Container is allowed to grow past 100.
如果你把UnconstrainedBox换成了CenterLimitedBox不会再体现 限制(因为它的限制仅仅体现在无限制父容器中),Container的上限是完全填充。

This explains the difference between a LimitedBox and a ConstrainedBox.
这个例子解释了LimitedBoxConstrainedBox 之间的不同。

Example 18

在这里插入图片描述

FittedBox(
   child: Text('Some Example Text.'),
)

The screen forces the FittedBox to be exactly the same size as the screen. The Text has some natural width (also called its intrinsic width) that depends on the amount of text, its font size, and so on.
屏幕强制了FittedBox的大小等同于屏幕的大小。 Text 有根据字数、字体大小决定的自然宽度(也可以说是固有宽度intrinsic width) 。

The FittedBox lets the Text be any size it wants, but after the Text tells its size to the FittedBox, the FittedBox scales the Text until it fills all of the available width.
FittedBoxText能够有任何自己想要的大小,但是当Text把自己的大小告诉了FittedBoxFittedBox会把Text缩放,直到把所有的有效空间都填充。

Example 19

在这里插入图片描述

Center(
   child: FittedBox(
      child: Text('Some Example Text.'),
   )
)

But what happens if you put the FittedBox inside of a Center widget? The Center lets the FittedBox be any size it wants, up to the screen size.
但是,如果你把FittedBox 塞到一个Center 里面,会发生什么?
Center 会让FittedBox展示任何不超过屏幕的大小。

The FittedBox then sizes itself to the Text, and lets the Text be any size it wants. Since both FittedBox and the Text have the same size, no scaling happens.
FittedBox 然后就会随着Text设置大小,并且让Text设置任何想要的大小。因为FittedBoxText有一样的大小,所以就没有缩放了。

Example 20

在这里插入图片描述

Center(
   child: FittedBox(
      child: Text('This is some very very very large text that is too big to fit a regular screen in a single line.'),
   )
)

However, what happens if FittedBox is inside of a Center widget, but the Text is too large to fit the screen?
但是,如果你把FittedBox 塞到一个Center 里面,而Text如果超过了屏幕大小,会发生什么?

FittedBox tries to size itself to the Text, but it can’t be bigger than the screen. It then assumes the screen size, and resizes Text so that it fits the screen, too.
FittedBox尝试去设置 Text的大小,但是它不能大于屏幕。它会推断屏幕的大小,然后重设置 Text的大小也适配屏幕。

Example 21

在这里插入图片描述

Center(
   child: Text('This is some very very very large text that is too big to fit a regular screen in a single line.'),
)

If, however, you remove the FittedBox, the Text gets its maximum width from the screen, and breaks the line so that it fits the screen.
然后,如果你移除了FittedBoxText会获取到来自屏幕的最大值,会自动换行,以此适配屏幕大小。

Example 22

在这里插入图片描述

FittedBox(
   child: Container(
      height: 20.0,
      width: double.infinity,
   )
)

FittedBox can only scale a widget that is bounded (has non-infinite width and height). Otherwise, it won’t render anything, and you’ll see an error in the console.
FittedBox 仅仅只能在边界范围内(有限的宽高)缩放子widget,与此相反的是(如果无限的情况),它不会绘制任何东西,并且你会在console上看到错误信息。

Example 23

在这里插入图片描述

Row(
   children:[
      Container(color: Colors.red, child: Text('This is a very long text that won’t fit the line.')),
      Container(color: Colors.green, child: Text('Goodbye!')),
   ]
)

The screen forces the Row to be exactly the same size as the screen.
屏幕会强制Row的大小等同于屏幕大小。

Just like an UnconstrainedBox, the Row won’t impose any constraints onto its children, and instead lets them be any size they want. The Row then puts them side-by-side, and any extra space remains empty.
就像UnconstrainedBoxRow不会强推constraints (属性)到子widget,相反的,是会让子widget设置自己想要的大小。Row只是把他们一个接着一个紧挨着排列,任何多余的空间继续保留着。

Example 24

在这里插入图片描述

Row(
   children:[
      Container(color: Colors.red, child: Text('This is a very long text that won’t fit the line.')),
      Container(color: Colors.green, child: Text('Goodbye!')),
   ]
)

Since Row won’t impose any constraints onto its children, it’s quite possible that the children might too big to fit the available width of the Row. In this case, just like an UnconstrainedBox, the Row displays the “overflow warning”.
因为Row 不会强推任何constraints到子widget,所以子widget很有可能会太大,超过了Row的范围。在这个例子里,就像UnconstrainedBoxRow显示了 “overflow warning”(内容溢出警告)。

Example 25

在这里插入图片描述

Row(
   children:[
      Expanded(
         child: Container(color: Colors.red, child: Text('This is a very long text that won’t fit the line.'))
      ),
      Container(color: Colors.green, child: Text('Goodbye!')),
   ]
)

When a Row’s child is wrapped in an Expanded ** widget, the Row won’t let this child define its own width anymore.
Row’s** 的子widget包裹着一个**Expanded **,Row不会让它的子widget再定义子的宽度。

Instead, it defines the **Expanded ** width according to the other children, and only then the **Expanded ** widget forces the original child to have the **Expanded’s ** width.
与此相对的,它根据子widget来定义了 **Expanded 的宽度,并且仅让Expanded ** widget 的强制最初的一个子widget适配 Expanded的宽度 。

In other words, once you use Expanded, the original child’s width becomes irrelevant, and is ignored.
换句话说,一旦你使用了Expanded,最初的子widget的宽度无关紧要了,会被忽略。

Example 26

在这里插入图片描述

Row(
   children:[
      Expanded(
         child: Container(color: Colors.red, child: Text(‘This is a very long text that won’t fit the line.)),
      ),
      Expanded(
         child: Container(color: Colors.green, child: Text(‘Goodbye!),
      ),
   ]
)

If all of Row’s children are wrapped in Expanded widgets, each Expanded has a size proportional to its flex parameter, and only then each Expanded widget forces its child to have the Expanded’s width.
如果,Row所有的子widget都包裹着Expanded,每个Expanded都有flex比例参数,每个Expanded强制子widget适配Expanded的宽度。

In other words, Expanded ignores the preferred width of its children.
换句话说,Expanded会忽略它的子widget的宽度。

Example 27

在这里插入图片描述

Row(children:[
  Flexible(
    child: Container(color: Colors.red, child: Text('This is a very long text that won’t fit the line.'))),
  Flexible(
    child: Container(color: Colors.green, child: Text(‘Goodbye!))),
  ]
)

The only difference if you use Flexible instead of Expanded, is that Flexible lets its child have the same or smaller width than the Flexible itself, while Expanded forces its child to have the exact same width of the Expanded. But both Expanded and Flexible ignore their children’s width when sizing themselves.
如果你使用的是Flexible而不是Expanded,不同之处是Flexible会让它的子widget的大小等同或者小于它自己的大小,而Expanded会让子widget精确的等于它自己的带下。共同的地方是ExpandedFlexible在确定子widget的大小的时候,都会忽略他们的子widget的大小。

Note: This means that it’s impossible to expand Row children proportionally to their sizes. The Row either uses the exact child’s width, or ignores it completely when you use Expanded or Flexible.
注意:这意味着当使用ExpandedFlexible的时候,你不可能去扩大Row的子widget的大小。Row也不会使用他的子widget的精确大小,只会是直接忽略掉子widget的宽度值。

Example 28

在这里插入图片描述

Row(children:[
  Flexible(
    child: Container(color: Colors.red, child: Text('This is a very long text that won’t fit the line.'))),
  Flexible(
    child: Container(color: Colors.green, child: Text(‘Goodbye!))),
  ]
)

The screen forces the Scaffold to be exactly the same size as the screen, so the Scaffold fills the screen. The Scaffold tells the Container that it can be any size it wants, but not bigger than the screen.
屏幕强制Scaffold的大小等同于自己的大小,所以Scaffold填充屏幕。Scaffold告诉Container,它可以设置任何大小,但是不能超过屏幕大小。

Note: When a widget tells its child that it can be smaller than a certain size, we say the widget supplies loose constraints to its child. More on that later.
注意:当一个widget告诉它的子widget:它可以小于某个明确的大小,我们可以说widget loose 了 子widget的 constraints。稍后细说。

Example 29

在这里插入图片描述

Scaffold(
	body: SizedBox.expand(
   	child: Container(
      color: blue,
      child: Column(
         children: [
            Text('Hello!'),
            Text('Goodbye!'),
         ],
      ))))

If you want the Scaffold’s child to be exactly the same size as the Scaffold itself, you can wrap its child with SizedBox.expand.
如果你想要Scaffold的子widget的大小等同Scaffold的大小,你可以让子widget包裹一个SizedBox来扩展。

Note: When a widget tells its child that it must be of a certain size, we say the widget supplies tight constraints to its child.
注意:当一个widged告诉它的子widget:它必须有一个明确的大小,我们就说widget应该tight一个constraints给他的子widget。

Tight vs. loose constraints

It’s very common to hear that some constraint is “tight” or “loose”, so it’s worth knowing what that means.
经常可以听到constraint的状态是“tight” 或者 “loose”,所以这是值得知道这意味着什么。

A tight constraint offers a single possibility, an exact size. In other words, a tight constraint has its maximum width equal to its minimum width; and has its maximum height equal to its minimum height.
一个 tight constraint 提供了一个单一的可能性,一个范围明确的大小尺寸,换句话说,一个ight constraint有maximum宽度 、minimum 宽度;maximum高度,minimum高度。

If you go to Flutter’s box.dart file and search for the BoxConstraints constructors, you’ll find the following:
如果你看flutter的 box.dart 文件,并且搜索BoxConstraints构造器,你会看到下述代码:

BoxConstraints.tight(Size size)
   : minWidth = size.width,
     maxWidth = size.width,
     minHeight = size.height,
     maxHeight = size.height;

If you revisit Example 2 above, it tells us that the screen forces the red Container to be exactly the same size as the screen. The screen does that, of course, by passing tight constraints to the Container.
如果你再看之前的Example 2 ,它告诉我们屏幕强制红色Container的大小等同于屏幕大小。屏幕当然这样做了,通过传递tight constraints 给到这个Container

A loose constraint, on the other hand, sets the maximum width and height, but lets the widget be as small as it wants. In other words, a loose constraint has a minimum width and height both equal to zero:
另外一方面,一个loose constraint, 设置了maximum宽高,但是会让widget按照自己的想法设置大小。换句话说,一个 loose constraint 同样有同于0的minimum宽高。

BoxConstraints.loose(Size size)
   : minWidth = 0.0,
     maxWidth = size.width,
     minHeight = 0.0,
     maxHeight = size.height;

If you revisit Example 3, it tells us that the Center lets the red Container be smaller, but not bigger than the screen. The Center does that, of course, by passing loose constraints to the Container. Ultimately, the Center’s very purpose is to transform the tight constraints it got from its parent (the screen) to loose constraints for its child (the Container).
如果你重看上面的 Example 3,它告诉我们:Center让红色的Container更小,并且不能超过屏幕大小。这个Center当然这样做了,通过传递一个loose constraints 给到Container。最终,Center从它的父容器widget获取到的 tight constraints ,有目的地转换成loose constraints ,再传给它的子widget (Container)。

Learning the layout rules for specific widgets

学习每个具体的widget的布局规则。

Knowing the general layout rule is necessary, but it’s not enough.
知道通用的布局规则是很有必要的 ,但是不够。

Each widget has a lot of freedom when applying the general rule, so there is no way of knowing what it will do by just reading the widget’s name.
当适通用的规则时,每个widget还有很多自由发挥,所以仅仅通过widget的名字,没法办法就知道它会怎么处理布局规则。

If you try to guess, you’ll probably guess wrong. You can’t know exactly how a widget behaves unless you’ve read its documentation, or studied its source-code.
如果你尝试盲猜,你可能会猜错。你不能精确的知道一个widget怎么表现,除非你去读了它的文档,或者读它的源代码。

The layout source-code is usually complex, so it’s probably better to just read the documentation. However, if you decide to study the layout source-code, you can easily find it by using the navigating capabilities of your IDE.
布局的源代码通常很复杂,所以可能读文档会更好。然而,如果你决定去学习布局的源码,你会更容易的去使用它来,精确的实现你的想法。

Here is an example:
这里是一个例子:
1、Find a Column in your code and navigate to its source code. To do this, use command+B (macOS) or control+B (Windows/Linux) in Android Studio or IntelliJ. You’ll be taken to the basic.dart file. Since Column extends Flex, navigate to the Flex source code (also in basic.dart).
1、在你的代码中选中Column,导航到它的源码。具体操作是,使用command+B (macOS) 或者 control+B (Windows/Linux) 在Android Studio or IntelliJ。你会找到 basic.dart file。因为导航到Flex源码(是在basic.dart文件中)。

2、Scroll down until you find a method called createRenderObject(). As you can see, this method returns a RenderFlex. This is the render-object for the Column. Now navigate to the source-code of RenderFlex, which takes you to the flex.dart file.
2、往下拉,直到你找到一个叫createRenderObject()的方法。这个时候你会看到,这个方法返回了一个RenderFlex。这就是Column的render-object(描绘对象)。现在,导航到RenderFlex的源码,你会定位到flex.dart 文件。

3、Scroll down until you find a method called performLayout(). This is the method that does the layout for the Column.
3、下拉知道你找到一个方法叫 performLayout()。这就是执行Column布局的具体方法。
在这里插入图片描述

Article by Marcelo Glasberg
论文作者:Marcelo Glasberg

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值