- 首先,上层 widget 向下层 widget 传递约束条件。
- 然后,下层 widget 向上层 widget 传递大小信息。
- 最后,上层 widget 决定下层 widget 的位置。
`
import 'package:flutter/material.dart';
class ConstraintPage extends StatelessWidget {
const ConstraintPage({super.key});
@override
Widget build(BuildContext context) {
//return style1();
//return style2();
//return style3();
//return style4();
//return style5();
//return style6();
//return style7();
//return style8();
//return style9();
//return style10();
//return style11();
//return style12();
//return style13();
//return style14();
//return style15();
//return style16();
//return style17();
//return style18();
//return style19();
//return style20();
//return style21();
//return style22();
//return style23();
//return style24();
//return style25();
//return style26();
//return style27();
//return style28();
return style29();
}
///样式1
///整个屏幕作为 Container 的父级,并且强制 Container 变成和屏幕一样的大小。
///所以这个 Container 充满了整个屏幕,并绘制成红色。
Widget style1() {
return Container(
color: Colors.red,
);
}
///样式2
///红色的 Container 想要变成 100 x 100 的大小, 但是它无法变成,因为屏幕强制它变成和屏幕一样的大小。
///所以 Container 充满了整个屏幕。
Widget style2() {
return Container(
width: 100,
height: 100,
color: Colors.red,
);
}
///样式3
///屏幕强制 Center 变得和屏幕一样大,所以 Center 充满了屏幕。
///然后 Center 告诉 Container 可以变成任意大小,但是不能超出屏幕。 现在,Container 可以真正变成 100 × 100 大小了。
Widget style3() {
return Center(
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
);
}
///样式4
///与上样例3不同的是,我们使用了 Align 而不是 Center。
///Align 同样也告诉 Container,你可以变成任意大小。 但是,如果还留有空白空间的话,它不会居中 Container。
///相反,它将会在允许的空间内,把 Container 放在右下角(bottomRight)。
Widget style4() {
return Align(
alignment: Alignment.bottomRight,
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
);
}
///样式5
///屏幕强制 Center 变得和屏幕一样大,所以 Center 充满屏幕。
///然后 Center 告诉 Container 可以变成任意大小,但是不能超出屏幕。 现在,Container 想要无限的大小,
///但是由于它不能比屏幕更大, 所以就仅充满屏幕。
Widget style5() {
return Center(
child: Container(
width: double.infinity,
height: double.infinity,
color: Colors.red,
),
);
}
///样式6
///屏幕强制 Center 变得和屏幕一样大,所以 Center 充满屏幕。
///然后 Center 告诉 Container 可以变成任意大小,但是不能超出屏幕。 由于 Container 没有子级而且没有固定大小,所以它决定能有多大就有多大, 所以它充满了整个屏幕。
///但是,为什么 Container 做出了这个决定? 非常简单,因为这个决定是由 Container widget 的创建者决定的。 可能会因创造者而异,而且你还得阅读 Container 文档 来理解不同场景下它的行为。
Widget style6() {
return Center(
child: Container(
color: Colors.red,
),
);
}
///样式7
///屏幕强制 Center 变得和屏幕一样大,所以 Center 充满屏幕。
///然后 Center 告诉红色的 Container 可以变成任意大小,但是不能超出屏幕。 由于 Container 没有固定大小但是有子级,所以它决定变成它 child 的大小。
///而它的 child 是一个想要 100 × 100 大小绿色的 Container。由于红色的 Container 和其子级一样大,所以也变为 100 × 100。由于绿色的 Container 完全覆盖了红色 Container, 所以你看不见它了。
Widget style7() {
return Center(
child: Container(
color: Colors.red,
child: Container(
color: Colors.green,
width: 100,
height: 100,
),
),
);
}
///样式8
///屏幕强制 Center 变得和屏幕一样大,所以 Center 充满屏幕。
///然后 Center 告诉红色的 Container 可以变成任意大小,但是不能超出屏幕。 由于 Container 没有固定大小但是有子级,所以它决定变成它 child 的大小。
///红色 Container 变为其子级的大小,但是它将其 padding 带入了约束的计算中。 所以它有一个 30 x 30 的外边距。由于这个外边距,所以现在你能看见红色了。 而绿色的 Container 则还是和之前一样。
Widget style8() {
return Center(
child: Container(
padding: const EdgeInsets.all(30),
color: Colors.red,
child: Container(
color: Colors.green,
width: 100,
height: 100,
),
),
);
}
///样式9
///你可能会猜想 Container 的尺寸会在 70 到 150 像素之间,但并不是这样。 ConstrainedBox 仅对其从其父级接收到的约束下施加其他约束。
///在这里,屏幕迫使 ConstrainedBox 与屏幕大小完全相同, 因此它告诉其子 Widget 也以屏幕大小作为约束, 从而忽略了其 constraints 参数带来的影响。
Widget style9() {
return ConstrainedBox(
constraints: const BoxConstraints(
minWidth: 70,
minHeight: 70,
maxWidth: 150,
maxHeight: 150,
),
child: Container(
color: Colors.red,
width: 10,
height: 10,
),
);
}
///样式10
///Center 允许 ConstrainedBox 达到屏幕可允许的任意大小。 ConstrainedBox 将 constraints 参数带来的约束附加到其子对象上。
///Container 必须介于 70 到 150 像素之间。虽然它希望自己有 10 个像素大小, 但最终获得了 70 个像素(最小为 70)
Widget style10() {
return Center(
child: ConstrainedBox(
constraints: const BoxConstraints(
minWidth: 70,
minHeight: 70,
maxWidth: 150,
maxHeight: 150,
),
child: Container(
color: Colors.red,
width: 10,
height: 10,
),
),
);
}
///样式11
///Center 允许 ConstrainedBox 达到屏幕可允许的任意大小。 ConstrainedBox 将 constraints 参数带来的约束附加到其子对象上。
///Container 必须介于 70 到 150 像素之间。 虽然它希望自己有 1000 个像素大小, 但最终获得了 150 个像素(最大为 150)。
Widget style11() {
return Center(
child: ConstrainedBox(
constraints: const BoxConstraints(
minWidth: 70,
minHeight: 70,
maxWidth: 150,
maxHeight: 150,
),
child: Container(
color: Colors.red,
width: 1000,
height: 1000,
),
),
);
}
///样式12
///Center 允许 ConstrainedBox 达到屏幕可允许的任意大小。 ConstrainedBox 将 constraints 参数带来的约束附加到其子对象上。
///Container 必须介于 70 到 150 像素之间。 虽然它希望自己有 100 个像素大小, 因为 100 介于 70 至 150 的范围内,所以最终获得了 100 个像素。
Widget style12() {
return Center(
child: ConstrainedBox(
constraints: const BoxConstraints(
minWidth: 70,
minHeight: 70,
maxWidth: 150,
maxHeight: 150,
),
child: Container(
color: Colors.red,
width: 100,
height: 100,
),
),
);
}
///样式13
///屏幕强制 UnconstrainedBox 变得和屏幕一样大,而 UnconstrainedBox 允许其子级的 Container 可以变为任意大小
///Container 是 20 x 50 ,所有最终获得 20 x 50 大小
Widget style13() {
return UnconstrainedBox(
child: Container(
color: Colors.red,
width: 20,
height: 50,
),
);
}
///样式14
///屏幕强制 UnconstrainedBox 变得和屏幕一样大, 而 UnconstrainedBox 允许其子级的 Container 可以变为任意大小。
///Container容器的高度为 50 像素,可以正常显示
///不幸的是,在这种情况下,Container容器的宽度为 4000 像素, 这实在是太大,以至于无法容纳在 UnconstrainedBox 中, 因此 UnconstrainedBox 将显示溢出警告(overflow warning)。
Widget style14() {
return UnconstrainedBox(
child: Container(
color: Colors.red,
width: 4000,
height: 50,
),
);
}
///样式15
///屏幕强制 OverflowBox 变得和屏幕一样大, 并且 OverflowBox 允许其子容器设置为任意大小。
///OverflowBox 与 UnconstrainedBox 类似,但不同的是, 如果其子级超出该空间,它将不会显示任何警告。
///在这种情况下,容器的宽度为 4000 像素,并且太大而无法容纳在 OverflowBox 中, 但是 OverflowBox 会全部显示,而不会发出警告。
Widget style15() {
return OverflowBox(
minWidth: 0.0,
minHeight: 0.0,
maxWidth: double.infinity,
maxHeight: double.infinity,
child: Container(color: Colors.red, width: 4000, height: 50),
);
}
///样式16
///UnconstrainedBox 让它的子级决定成为任何大小, 但是其子级是一个具有无限大小的 Container。
///Flutter 无法渲染无限大的东西,所以它抛出以下错误: BoxConstraints forces an infinite width.(盒子约束强制使用了无限的宽度)
Widget style16() {
return UnconstrainedBox(
child: Container(
color: Colors.red,
width: double.infinity,
height: 100,
));
}
///样式17
///UnconstrainedBox 让它的子级决定成为任何大小, 但是其子级是一个具有无限大小的 Container。
///Flutter 无法渲染无限大的东西,所以它抛出以下错误: BoxConstraints forces an infinite width.(盒子约束强制使用了无限的宽度)
///这次你就不会遇到报错了。 UnconstrainedBox 给 LimitedBox 一个无限的大小; 但它向其子级传递了最大为 100 的约束。
///如果你将 UnconstrainedBox 替换为 Center, 则LimitedBox 将不再应用其限制(因为其限制仅在获得无限约束时才适用), 并且容器的宽度允许超过 100。
///LimitedBox 和 ConstrainedBox 之间的区别。
Widget style17() {
return UnconstrainedBox(
child: LimitedBox(
maxWidth: 100,
child: Container(
color: Colors.red,
width: double.infinity,
height: 100,
),
),
);
/* return Center(
child: LimitedBox(
maxWidth: 100,
child: Container(
color: Colors.red,
width: double.infinity,
height: 100,
),
),
);*/
}
///样式18
///屏幕强制 FittedBox 变得和屏幕一样大, 而 Text 则是有一个自然宽度(也被称作 intrinsic 宽度), 它取决于文本数量,字体大小等因素。
///FittedBox 让 Text 可以变为任意大小。 但是在 Text 告诉 FittedBox 其大小后, FittedBox 缩放文本直到填满所有可用宽度。
Widget style18() {
return const FittedBox(
child: Text('Some Example Text.'),
);
}
///样式19
///但如果你将 FittedBox 放进 Center widget 中会发生什么? Center 将会让 FittedBox 能够变为任意大小, 取决于屏幕大小。
///FittedBox 然后会根据 Text 调整自己的大小, 然后让 Text 可以变为所需的任意大小, 由于二者具有同一大小,因此不会发生缩放。
Widget style19() {
return const Center(
child: FittedBox(
child: Text('Some Example Text.'),
));
}
///样式20
///然而,如果 FittedBox 位于 Center 中, 但 Text 太大而超出屏幕,会发生什么?
///FittedBox 会尝试根据 Text 大小调整大小, 但不能大于屏幕大小。然后假定屏幕大小, 并调整 Text 的大小以使其也适合屏幕。
Widget style20() {
return const 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.',
),
),
);
}
///样式21
///然而,如果你删除了 FittedBox, Text 则会从屏幕上获取其最大宽度, 并在合适的地方换行。
Widget style21() {
return const Center(
child: Text(
'This is some very very very large text that is too big to fit a regular screen in a single line.',
),
);
}
///样式22
///FittedBox 只能在有限制的宽高中 对子 widget 进行缩放(宽度和高度不会变得无限大)。 否则,它将无法渲染任何内容,并且你会在控制台中看到错误。
///RenderConstrainedBox object was given an infinite size during layout.
Widget style22() {
return FittedBox(
child: Container(
height: 20.0,
width: double.infinity,
),
);
}
///样式23
///屏幕强制 Row 变得和屏幕一样大,所以 Row 充满屏幕。
///和 UnconstrainedBox 一样, Row 也不会对其子代施加任何约束, 而是让它们成为所需的任意大小。 Row 然后将它们并排放置, 任何多余的空间都将保持空白。
Widget style23() {
return Row(
children: [
Container(
color: Colors.red,
child: const Text(
'Hello!',
style: TextStyle(color: Colors.black, fontSize: 12),
),
),
Container(
color: Colors.green,
child: const Text('Goodbye!'),
),
],
);
}
///样式24
///由于 Row 不会对其子级施加任何约束, 因此它的 children 很有可能太大 而超出 Row 的可用宽度。在这种情况下, Row 会和 UnconstrainedBox 一样显示溢出警告。
Widget style24() {
return Row(
children: [
Container(
color: Colors.red,
child: const Text(
'This is a very long text that won’t fit the line.',
),
),
Container(
color: Colors.green,
child: const Text(
'Goodbye!',
),
),
],
);
}
///样式25
///当 Row 的子级被包裹在了 Expanded widget 之后, Row 将不会再让其决定自身的宽度了。
///取而代之的是,Row 会根据所有 Expanded 的子级 来计算其该有的宽度。
///换句话说,一旦你使用 Expanded, 子级自身的宽度就变得无关紧要,直接会被忽略掉。
Widget style25() {
return Row(
children: [
Expanded(
child: Container(
color: Colors.red,
child:
const Text('This is a very long text that won’t fit the line.'),
),
),
Container(
color: Colors.green,
child: const Text('Goodbye!'),
),
],
);
}
///样式26
///如果所有 Row 的子级都被包裹了 Expanded widget, 每一个 Expanded 大小都会与其 flex 因子成比例, 并且 Expanded widget 将会强制其子级具有与 Expanded 相同的宽度。
///换句话说,Expanded 忽略了其子 Widget 想要的宽度。
Widget style26() {
return Row(
children: [
Expanded(
child: Container(
color: Colors.red,
child:
const Text('This is a very long text that won’t fit the line.'),
),
),
Expanded(
child: Container(
color: Colors.green,
child: const Text('Goodbye!'),
),
),
],
);
}
///样式27
///如果你使用 Flexible 而不是 Expanded 的话, 唯一的区别是,Flexible 会让其子级具有与 Flexible 相同或者更小的宽度。
///而 Expanded 将会强制其子级具有和 Expanded 相同的宽度。 但无论是 Expanded 还是 Flexible 在它们决定子级大小时都会忽略其宽度。
///
/// Row 要么使用子级的宽度, 要么使用Expanded 和 Flexible 从而忽略子级的宽度。
Widget style27() {
return Row(
children: [
Flexible(
child: Container(
color: Colors.red,
child: const Text(
'This is a very long text that won’t fit the line.',
style: TextStyle(fontSize: 12),
),
),
),
Flexible(
child: Container(
color: Colors.green,
child: const Text('Goodbye!'),
),
),
],
);
}
///样式28
///屏幕强制 Scaffold 变得和屏幕一样大, 所以 Scaffold 充满屏幕。 然后 Scaffold 告诉 Container 可以变为任意大小, 但不能超出屏幕。
///
/// 当一个 widget 告诉其子级可以比自身更小的话, 我们通常称这个 widget 对其子级使用 宽松约束(loose)。
Widget style28() {
return Scaffold(
body: Container(
color: Colors.blue,
child: Column(
children: const [
Text('Hello!'),
Text('Goodbye!'),
Text(' Flexible 从而忽略子级的宽度。!'),
],
),
),
);
}
///样式29
///如果你想要 Scaffold 的子级变得和 Scaffold 本身一样大的话, 你可以将这个子级外包裹一个 SizedBox.expand。
///
/// 当一个 widget 告诉它的子级必须变成某个大小的时候, 我们通常称这个 widget 对其子级使用 严格约束(tight)。
Widget style29() {
return Scaffold(
body: SizedBox.expand(
child: Container(
color: Colors.blue,
child: Column(
children: const [
Text('Hello!'),
Text('Goodbye!'),
Text(' Flexible 从而忽略子级的宽度。!'),
Text(' Flexible 。!'),
],
),
),
),
);
}
///严格约束(Tight) vs 宽松约束(loose)
///以后你经常会听到一些约束为严格约束或宽松约束, 你花点时间来弄明白它们是值得的。
///严格约束给你了一种获得确切大小的选择。 换句话来说就是,它的最大/最小宽度是一致的,高度也一样。
/// 如果你到 Flutter 的 box.dart 文件中搜索 BoxConstraints 构造器,你会发现以下内容:
///BoxConstraints.tight(Size size): minWidth = size.width,maxWidth = size.width,minHeight = size.height, maxHeight = size.height;
///如果你重新阅读 样例 2, 它告诉我们屏幕强制 Container 变得和屏幕一样大。 为何屏幕能够做到这一点, 原因就是给 Container 传递了严格约束。
///一个宽松约束换句话来说就是设置了最大宽度/高度, 但是让允许其子 widget 获得比它更小的任意大小。 换句话来说,宽松约束的最小宽度/高度为 0。
///BoxConstraints.loose(Size size): minWidth = 0.0,maxWidth = size.width,minHeight = 0.0,maxHeight = size.height;
///如果你访问 样例 3, 它将会告诉我们 Center 让红色的 Container 变得更小, 但是不能超出屏幕。Center 能够做到这一点的原因就在于 给 Container 的是一个宽松约束。
///总的来说,Center 起的作用就是从其父级(屏幕)那里获得的严格约束, 为其子级(Container)转换为宽松约束。
}
`