搞懂Flutter的布局约束
Flutter布局通常会出现一些奇怪的现象,例如,我希望一个Container是100宽高的正方形,于是我这样写
void main() => runApp(Home());
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.amber,
width: 100,
height: 100,
);
}
}
但是结果却是全屏.
感觉难以理解,出现这种情况的原因是,Flutter布局方式是对Widget Tree先进行自上而下对每个Widget进行约束(Constraint 过程),再自下而上决定每个Widget的大小(Size 过程),最后由父Widget决定每个子Widget的位置.总结下来就三步
1,向下Constraint
2,向上Size
3,父Widget决定位置
这里我们来解释一下上面的代码为什么会白屏.
在第一步过程中屏幕是Container的父亲,屏幕给Container的约束是和屏幕一样大,在向上Size的过程中,这里我们必须理解的是,不是子Widget想多大就多大,它必须考虑它的约束后给出一个大小,这里虽然它是宽100,高100不过约束强制它全屏了,所以向上Size的时候它就是全屏大小,最后父亲也就是屏幕决定它的位置,也就是坐标(0,0).
我们改一下代码
void main() => runApp(Home());
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Container(
color: Colors.amber,
width: 100,
height: 100,
),
);
}
}
现在我们对Container包裹了一个Center,运行后是
现在和我们希望的样子一样了,因为现在的Center对于它子Widget的约束不是屏幕大小了,而是子Widget它希望自己多大就多大,最后Center决定Container的位置是居中,这样就看到了运行后的效果了。
这里可能会有个疑问是,为什么屏幕对于子Widget的约束是全屏幕大小,而Center对于它子Widget的约束却是它希望多大就多大呢?我怎么知道一个父Widget的是怎么约束子Widget的呢?
对于屏幕它是作为一个最上层的父亲,它给予第一个Widget(根Widget)的约束就是屏幕大小,无论根Widget怎么设置自己大小都授全屏约束。接下来Widget的约束就是根据具体情况具体定了(视Widget类型,剩余空间等影响,具体情况具体分析)
下面我们再来一个例子
void main() => runApp(Home());
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Container(
color: Colors.amber,
width: 100,
height: 100,
),
);
}
}
运行后变成这样
又是全屏了,这里证明了Container对于子Widget约束是撑满的. 那么我不想撑满,除了之前提到的Center还有哪些方式呢?
1,使用Align
Align可以用来对齐一个Widget,同时它对子Widget的大小约束是子widget想多大就多大.(当然这里还需要满足Align父亲的约束).
void main() => runApp(Home());
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.centerLeft,
child: Container(
color: Colors.amber,
width: 100,
height: 100,
),
);
}
}
2,使用Stack
void main() => runApp(Home());
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Stack(
textDirection: TextDirection.ltr,
children: [
Container(
color: Colors.amber,
width: 100,
height: 100,
)
],
);
}
}
当然还有其它Widget是对子Widget的大小约束是子widget想多大就多大,具体这里就不一一列举了.
最后再来看一个Colum的例子,回顾下布局约束的整个流程.
void main() => runApp(Home());
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
Container(
color: Colors.amber,
width: 100,
height: 100,
),
Container(
color: Colors.red,
width: 100,
height: 100,
),
Container(
color: Colors.blue,
width: 100,
height: 100,
),
],
);
}
}
我们来分析一遍
1,Column作为第一个Widget,自然是全屏.
2,在Column约束下,三个Container需要100的宽高,Column都能满足它们的要求
3,根据Column的布局特性决定三个Container的位置.
结语:
Flutter中Widget不能决定它自己的大小和位置,必须要结合父Widget的约束去决定,同样父Widget也有父Widget,所以我们在指定Widget的位置和大小的时候一定要把父Widget的约束考虑进去.
来源:juejin.cn/post/7217770698784555064