Flutter 布局真经(1)
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。既有适合小白学习的零基
- 最后,widget 将会把它的大小信息向上传递至父 widget(包括其原始约束条件)。
官方对话(构建一个带有padding的column):
Widget: “嘿!我的父级。我的约束是多少?”
Parent: “你的宽度必须在
80到300像素之间,高度必须在30到85之间。”
Widget: “嗯…我想要
5个像素的内边距,这样我的子级能最多拥有290个像素宽度和75个像素高度。”
Widget: “嘿,我的第一个子级,你的宽度必须要在
0到290,长度在0到75之间。”
First child: “OK,那我想要
290像素的宽度,20个像素的长度。”
Widget: “嗯…由于我想要将我的第二个子级放在第一个子级下面,所以我们仅剩
55个像素的高度给第二个子级了。”
Widget: “嘿,我的第二个子级,你的宽度必须要在
0到290,长度在0到55之间。”
Second child: “OK,那我想要
140像素的宽度,30个像素的长度。”
Widget: “很好。我的第一个子级将被放在
x: 5&y: 5的位置,而我的第二个子级将在x: 80&y: 25的位置。”
Widget: “嘿,我的父级,我决定我的大小为
300像素宽度,60像素高度。”
====================================================================
约束Constraints 在Flutter中是一种_布局协议_,Flutter中有两大布局协议BoxConstraints和SliverConstraints。对于非滑动的控件例如Padding,Flex等一般都使用_BoxConstraints盒约束_。
约束可以分为:宽松约束(loose)和 严格约束(tight) 就widget布局树而言,约束默认向下传递,可有些布局类复写了performLayout改变了约束行为,将向下传递的约束信息改变甚至重建,从而导致有些布局行为变得不可预测,因此就需要掌握一些常用布局的布局原理,才能对整体的布局行为加以分析。
案例一:Container的约束失效
ConstrainedBox(
constraints: BoxConstraints.tightFor(
width: double.infinity,
height: double.infinity),
child: Container(width: 100, height: 100, color: red)
)
上边的案例,展示了一个预期宽100,高100的红色方块,可实际上只会得到一个满屏幕的红色。 虽然Container内部有宽高的约束,但是在这里是不起作用的,究其原因,是因为Container内部的布局特性引起的,父部件传递一个tight紧布局,而到了Container由于内部使用的ConstrainedBox,其布局行为会做如下改变:
@override
// this.constraints 为父部件传递的约束
void performLayout() {
final BoxConstraints constraints = this.constraints; // this.constraints为父部件传递过来的约束
if (child != null) {
// 在这里改变了约束,可能会导致自身设置的约束失效
child!.layout(_additionalConstraints.enforce(constraints),
parentUsesSize: true);
size = child!.size;
} else {
size = _additionalConstraints.enforce(constraints).constrain(Size.zero);
}
}
// clamp方法会自行在约束范围境内选择
BoxConstraints enforce(BoxConstraints constraints) {
return BoxConstraints(
minWidth: minWidth.clamp(constraints.minWidth, constraints.maxWidth),
maxWidth: maxWidth.clamp(constraints.minWidth, constraints.maxWidth),
minHeight: minHeight.clamp(constraints.minHeight, constraints.maxHeight),
maxHeight: maxHeight.clamp(constraints.minHeight, constraints.maxHeight),
);
}
按照先前的布局原理来说,Container告诉父布局自己需要一个100x100的空间,而父布局也有充分的空间提供,那预期的效果应该会很好的呈现,可在这里由于ConstrainedBox内部改变了布局行为,导致预期结果不生效,ConstrainedBox会通过enforce函数衡量自身的约束属性即 _additionalConstraints,和父布局传递的约束,在其中取临近值,在这里由于父部件约束为:
BoxConstraints(
minWidth: double.infinity,
maxWidth: double.infinity,
minHeight: double.infinity,
maxHeight: double.infinity,
);
故所以_additionalConstraints的约束行为会被改成double.infinity~double.infinity之间的值即double.infinity。
案例二:奇怪的LimitedBox
现有这样两个场景:
ConstrainedBox(
constraints: BoxConstraints.tightFor(
width: double.infinity,
height: double.infinity),
child: UnconstrainedBox(
child: LimitedBox(
maxWidth: 100,
child:
Container(color: Colors.red, width: double.infinity, height: 100),
),
)
)
ConstrainedBox(
constraints: BoxConstraints.tightFor(
width: double.infinity,
height: double.infinity),
child: Center(
child: LimitedBox(
maxWidth: 100,
child:
Container(color: Colors.red, width: double.infinity, height: 100),
),
)
)
两者的区别不是很明显,只是前者的LimitedBox由UnconstrainedBox包裹,而后由Center包裹,但两个例子所展示的UI却大相径庭: 

这样看来是Center致使LimitedBox的maxWidth约束失效了,为什么会这样呢?
// LimitedBox的布局过程
BoxConstraints _limitConstraints(BoxConstraints constraints) {
return BoxConstraints(
minWidth: constraints.minWidth,
// 判断是否有边界,如果有,则maxWidth会失效
maxWidth: constraints.hasBoundedWidth ? constraints.maxWidth : constraints.constrainWidth(maxWidth),
minHeight: constraints.minHeight,
maxHeight: constraints.hasBoundedHeight
-
? constraints.maxHeight
- constraints.constrainHeight(maxHeight),
);
}
@override
void performLayout() {
if (child != null) {
final BoxConstraints constraints = this.constraints;
child!.layout(_limitConstraints(constraints), parentUsesSize: true);
size = constraints.constrain(child!.size);
} else {
size = _limitConstraints(constraints).constrain(Size.zero);
}
}
bool get hasBoundedWidth => maxWidth < double.infinity;
引起LimitedBox的maxWidth失效的原因已经很明显了, 关键就在于这行代码:
constraints.hasBoundedWidth ? constraints.maxWidth : constraints.constrainWidth(maxWidth)
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。




既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
…(img-0nuyH9bf-1715559560336)]
[外链图片转存中…(img-nwJtJExN-1715559560338)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
更多推荐



所有评论(0)