前言:Flutter系列的文章我应该会持续更新至少一个月左右,从User Interface(UI)到数据相关(文件、数据库、网络)再到Flutter进阶(平台特定代码编写、测试、插件开发等),欢迎感兴趣的读者持续关注(可以扫描左边栏二维码或者微信搜索”IT工匠“关注微信公众号哦,会同步推送)。
盒约束是指Widget
可以按照指定限制条件来决定自身如何占用布局空间,所谓的**“盒”**即指的是绘制自身的渲染框,或者理解为绘制自身的"画布"
。
概述
在Flutter
中,Widget
是在其基础渲染框(RenderBox
)对象之上渲染的,渲染框的父级Widget
会给出渲染框应该遵循的约束,然后渲染框在遵循给定约束的前提下自行调整自己的尺寸,这里的约束包括最小/最大宽度、最小/最大高度,而尺寸则指的是特定的宽度和高度、
一般来说,根据处理约束的方式分类,可以将渲染框分为三类:
- 第一类:遵循尺寸尽可能大原则的,比如
Center
和ListView
的渲染框 - 第二类:遵循尺寸尽可能和子
Widget
保持相同尺寸的,比如Transform
和Opacity
的渲染框 - 第三类:遵循尺寸尽可能成为指定尺寸的,比如
Image
和Text
的渲染框
某些Widget
(例如Container
)根据传入其构造函数的参数的不同而遵循不同的原则,以Container
为例,默认情况下它会尝试让自己的尺寸尽可能大(即遵循第一类原则),但是如果你给它设置一个宽度(width
),他将尽可能使自身的宽度和给定的宽度一样(即遵循第三类原则)。
其他的,像Row
和Column
(弹性框)会根据给出的不同约束而变化,如下面**“Flex”**部分所述。
约束有时是**“紧密的”**,这意味着它们没有留下让渲染框自己决定尺寸的空间(例如,如果最小和最大宽度相同,那么渲染框就没有调整的余地)。这个主要的例子是App Widget
,它是RenderView
类中包含的一个Widget
,主要特点是应用程序的build()
函数返回的子Widget
的渲染框被指定了一个约束,强制它完全填充应用程序的内容区域(通常是整个屏幕)。
Flutter
中的许多渲染框,特别是那些只带一个子Widget
的渲染框,都会将约束传递给子Widget
。这意味着如果你在应用程序的渲染树的根部嵌套了多个渲染框,那么子节点会受到所有的这些渲染框的约束。
有些渲染框是**“放松的”**,即约束中有最大值,但没有最小值,比如Center
的渲染框。
无边界约束
在某些情况下,渲染框的约束是无边界(无限)的, 这意味着最大宽度或最大高度设置为double.INFINITY
。
当将一个无边界的约束加到遵循尺寸尽可能大原则(即第一类原则)的渲染框之上时,渲染框将无法正常工作,在调试模式下,会抛出异常。
渲染框具有边界约束的最常见情况是在弹性框(Row
和Column
)内,以及可滚动区域(ListView
和其他ScrollView
子类)内。
特别是,ListView
尝试扩充以适应其横向可用的空间(即,如果它是一个垂直滚动块,它会尝试与其父Widget
一样宽)。 如果在水平滚动的ListView
中嵌套垂直滚动的ListView
,则内部的ListView
会尽可能宽,这是无限宽的,因为外部滚动区域可以在水平方向上一直滚动。
Flex
Flex
渲染框本身(Row
和Column
)根据它们在给定方向上处于有边界约束还是无边界约束的不同会表现出不同的行为。
在有边界约束下,他们会尝试在这个方向上尽可能大(遵循第一类原则)。
在边界约束下,他们试图让子Widget
在这个方向自适应。 在这种情况下,您不能将子Widget
上的flex
设置为0(默认值)以外的任何值。 在Widget
库中,这意味着当Flex
框位于另一个弹性框内或可滚动的渲染框内部时,你不能使用Expanded
。 如果你这样做,将会抛出异常。
在横向上,即在Column
的宽度和在Row
的高度上,它们必须永远不能是无边界的,否则它们将无法合理地对齐它们的子Widget
。