flutter3.0学习笔记

Flutter布局约束

Preview
  • 布局约束规则
  • 实例1
  • 实例2
  • 实例3
  • 实例4
  • 实例5
  • 实例6
  • 实例7
  • 实例8 (ConstrainedBox)
  • 实例9 (ConstrainedBox)
  • 实例10 (UnconstrainedBox)
  • 实例11 (UnconstrainedBox)
  • 实例12 (UnconstrainedBox)
  • 实例13 (UnconstrainedBox和LimitedBox)
  • 实例14 (OverflowBox)
  • 实例15 (FittedBox)
  • 严格约束(Tight) vs 宽松约束(loose)

布局约束规则

首先,上层 widget 向下层 widget 传递约束条件,然后,下层 widget 向上层 widget 传递大小信息,最后,上层 widget 决定下层 widget 的位置。

  • 一个 widget 仅在其父级给其约束的情况下才能决定自身的大小。这意味着 widget 通常情况下 不能任意获得其想要的大小。

  • 一个widget无法知道,也不需要决定其在屏幕中的位置。因为它的位置是由其父级决定的。

  • 当轮到父级决定其大小和位置的时候,同样的也取决于它自身的父级。所以,在不考虑整棵树的情况下,几乎不可能精确定义任何 widget 的大小和位置。

  • 如果子级想要拥有和父级不同的大小,然而父级没有足够的空间对其进行布局的话,子级的设置的大小可能会不生效。 这时请明确指定它的对齐方式。

实例1

import 'package:flutter/material.dart';

class LayoutPage extends StatelessWidget {
  const LayoutPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
    );
  }
}

整个屏幕作为 Container 的父级,并且强制 Container 变成和屏幕一样的大小。 所以这个 Container 充满了整个屏幕,并绘制成红色。

实例2

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

红色的 Container 想要变成 100 x 100 的大小,但是它无法变成,因为屏幕强制它变成和屏幕一样的大小。所以 Container 充满了整个屏幕。 image.png

实例3

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

屏幕强制 Center 变得和屏幕一样大,所以 Center 充满了屏幕。 然后 Center 告诉 Container 可以变成任意大小,但是不能超出屏幕。现在,Container 可以真正变成 100 × 100 大小了。

image.png

实例4

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

与上一个样例不同的是,我们使用了 Align 而不是 CenterAlign 同样也告诉 Container,你可以变成任意大小。Align默认居中。

实例5

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

屏幕强制 Center 变得和屏幕一样大,所以 Center 充满屏幕。 然后 Center 告诉 Container 可以变成任意大小,但是不能超出屏幕。现在,Container 想要无限的大小,但是由于它不能比屏幕更大,所以就仅充满屏幕。

实例6

return Center(
  child: Container(
    color: Colors.red,
    child: Container(
      color: Colors.green,
      width: 50,
      height: 50,
    ),
  ),
);

屏幕强制 Center 变得和屏幕一样大,所以 Center 充满屏幕。

然后 Center 告诉红色的 Container 可以变成任意大小,但是不能超出屏幕。由于 Container 没有固定大小但是有子级,所以它决定变成它 child 的大小。

然后红色的 Container 告诉它的 child 可以变成任意大小,但是不能超出屏幕。

而它的 child 是一个想要 50 × 50 大小绿色的 Container。由于红色的 Container 和其子级一样大,所以也变为 50 × 50。由于绿色的 Container 完全覆盖了红色 Container,所以你看不见它了。

image.png

实例7

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

红色 Container 变为其子级的大小,但是它将其 padding 带入了约束的计算中。所以它有一个 20 x 20 的外边距。由于这个外边距,所以现在你能看见红色了。而绿色的 Container 则还是和之前一样。 image.png

实例8 (ConstrainedBox)

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

你可能会猜想 Container 的尺寸会在 70 到 150 像素之间,但并不是这样。 ConstrainedBox 仅对其从其父级接收到的约束下施加其他约束。

在这里,屏幕迫使 ConstrainedBox 与屏幕大小完全相同,因此它告诉其子 Widget 也以屏幕大小作为约束,从而忽略了其 constraints 参数带来的影响。

image.png

实例9 (ConstrainedBox)

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

现在,Center 允许 ConstrainedBox 达到屏幕可允许的任意大小。 ConstrainedBoxconstraints 参数带来的约束附加到其子对象上。

Container 必须介于 70 到 150 像素之间。虽然它希望自己有 20 个像素大小,但最终获得了 70 个像素(最小为 70)。

image.png

实例10 (UnconstrainedBox)

 return UnconstrainedBox(
  child: Container(
    color: Colors.red,
    width: 30,
    height: 50,
  ),
);

屏幕强制 UnconstrainedBox 变得和屏幕一样大,而 UnconstrainedBox 允许其子级的 Container 可以变为任意大小。

image.png

实例11 (UnconstrainedBox)

return UnconstrainedBox(
  child: Container(
    color: Colors.red,
    width: 3000,
    height: 50,
  ),
);

屏幕强制 UnconstrainedBox 变得和屏幕一样大,而 UnconstrainedBox 允许其子级的 Container 可以变为任意大小。

不幸的是,在这种情况下,容器的宽度为 3000 像素,这实在是太大,以至于无法容纳在 UnconstrainedBox 中,因此 UnconstrainedBox 将显示溢出警告(overflow warning)。

image.png

实例12 (UnconstrainedBox)

return UnconstrainedBox(
  child: Container(
    color: Colors.red,
    width: double.infinity,
    height: 50,
  ),
);

这将不会渲染任何东西,而且你能在控制台看到错误信息。

UnconstrainedBox 让它的子级决定成为任何大小,但是其子级是一个具有无限大小的 Container

Flutter 无法渲染无限大的东西,所以它抛出以下错误: BoxConstraints forces an infinite width.(盒子约束强制使用了无限的宽度)

image.png

实例13 (UnconstrainedBox和LimitedBox)

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

这次你就不会遇到报错了。 UnconstrainedBoxLimitedBox 一个无限的大小;但它向其子级传递了最大为 100 的约束。

如果你将 UnconstrainedBox 替换为 Center,则LimitedBox 将不再应用其限制(因为其限制仅在获得无限约束时才适用),并且容器的宽度允许超过 100。

上面的样例解释了 LimitedBoxConstrainedBox 之间的区别。

image.png

实例14 (OverflowBox)

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

屏幕强制 OverflowBox 变得和屏幕一样大,并且 OverflowBox 允许其子容器设置为任意大小。

OverflowBoxUnconstrainedBox 类似,但不同的是,如果其子级超出该空间,它将不会显示任何警告。

在这种情况下,容器的宽度为 3000 像素,并且太大而无法容纳在 OverflowBox 中,但是 OverflowBox 会全部显示,而不会发出警告。

image.png

实例15 (FittedBox)

return  const FittedBox(
  child: Text('Some Example Text.'),
);

屏幕强制 FittedBox 变得和屏幕一样大,而 Text 则是有一个自然宽度(也被称作 intrinsic 宽度),它取决于文本数量,字体大小等因素。

FittedBoxText 可以变为任意大小。但是在 Text 告诉 FittedBox 其大小后, FittedBox 缩放文本直到填满所有可用宽度。

image.png

严格约束(Tight) vs 宽松约束(loose)

  • 严格约束(Tight BoxConstraints 构造器:
BoxConstraints.tight(Size size)
   : minWidth = size.width,
     maxWidth = size.width,
     minHeight = size.height,
     maxHeight = size.height;

实例2告诉我们屏幕强制 Container 变得和屏幕一样大。为何屏幕能够做到这一点,原因就是给 Container 传递了严格约束。

  • 宽松约束(loose) 一个 宽松 约束,换句话来说就是设置了最大宽度/高度,但是让允许其子 widget 获得比它更小的任意大小。换句话来说,宽松约束的最小宽度/高度为 0。
BoxConstraints.loose(Size size)
   : minWidth = 0.0,
     maxWidth = size.width,
     minHeight = 0.0,
     maxHeight = size.height;

Center 让红色的 Container 变得更小,但是不能超出屏幕。Center 能够做到这一点的原因就在于给 Container 的是一个宽松约束。总的来说,Center 起的作用就是从其父级(屏幕)那里获得的严格约束,为其子级(Container)转换为宽松约束。