对于写过Flutter的开发者来说,我敢肯定,大部分的开发者都不能准确预测这次Hot Reload之后,布局是否是自己想要的结果。Flutter的布局与Native的布局方式非常不同,所以,了解Flutter这茫茫多的布局组件,是我们准确布局的基础。
在Flutter中,有一堆Box布局组件,它们可以用来更加精确的调整布局,下面我们就来看看这些Box都有哪些作用。
ConstrainedBox
ConstrainedBox用于限制Child Widget的尺寸约束,例如:
- 让Text最宽100,从而实现多行
- 固定Widget最大最小尺寸
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 100,
),
child: const Text(
'xuyisheng',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 50,
),
),
),
ConstrainedBox(
constraints: const BoxConstraints(
minHeight: 100,
),
child: ElevatedButton(
child: const Text('Flutter'),
onPressed: () {},
),
),
],
),
)
效果如图所示。
UnconstrainedBox
UnconstrainedBox的作用正好和ConstrainedBox相反。它可以破除组件本身的约束规则,从而更方便的进行布局。
例如下面这个例子:
代码语言:javascript复制Center(
child: Container(
color: Colors.blue,
width: 300,
height: 300,
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
),
)
由于Container的布局规则,内部的Container被设置为父Widget尺寸,从而忽略了子Widget的尺寸设置,所以,这里使用UnconstrainedBox来解除这种约束:
代码语言:javascript复制Center(
child: Container(
color: Colors.blue,
width: 300,
height: 300,
child: UnconstrainedBox(
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
),
),
)
从而可以让内部的Container按照自身尺寸进行布局。
更加灵活一点,我们还可以选择保留某一方向上的约束:constrainedAxis: Axis.horizontal。
SizedBox
SizedBox有下面几个使用场景:
- 当你需要一个确切尺寸的Widget时,通过SizedBox来进行约束
- 在父容器中撑满剩余空间
- 在没有child的情况下,对空间做分割
场景1:
代码语言:javascript复制SizedBox(
width: 200,
height: 200,
child: Text(
'xuyisheng',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 50,
),
),
)
场景2:某方向上的double.infinity,会在父级允许的尺寸下尽可能多的拓展。
代码语言:javascript复制Center(
child: Container(
color: Colors.red,
width: 200,
height: 200,
child: Center(
child: Container(
color: Colors.blue,
child: const SizedBox(
width: double.infinity,
height: 100,
child: Text(
'xuyisheng',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 50,
),
),
),
),
),
),
)
展示效果如图所示。
如果width和height方向上都是撑满父Widget的剩余空间,那么可以使用SizedBox.expand来简写。
还有一个便捷方法——SizedBox.shrink,它的作用是让尺寸在父容器的约束下尽可能的小,如果父容器不设置minWidth或者minHeight,那么它的尺寸就是0,这个属性通常和BoxConstraints一起配合使用。
FractionallySizedBox
这是Flutter给你提供的一个百分百布局工具。通常用于在父容器中,按照百分比来进行布局。
代码语言:javascript复制Center(
child: Container(
color: Colors.red,
width: 200,
height: 200,
child: const FractionallySizedBox(
widthFactor: 0.5,
heightFactor: 0.5,
child: Text(
'xuyisheng',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 50,
),
),
),
),
)
展示效果如图所示。
和SizedBox一样,它也可以用于作为Widget直接的间隔,只不过它使用的是百分比作为单位,总量是父容器的尺寸。
如果使用Flexible组件包裹FractionallySizedBox,那么就可以适用于Row和Column。
要注意的是,widthFactor和heightFactor是可以大于1的,也就是说,子Widget可以超出父容器展示。
LimitedBox
当Widget没有父级来限制它们的尺寸时,如何在Widget上设置它的默认大小呢?这就需要使用到LimitedBox了。
LimitedBox只在父容器没有提供尺寸约束时,对子Widget的尺寸进行默认约束,在在Listview和Column、Row中是非常有用的。
❝如果外部容器对Child设置了尺寸约束,那么LimitedBox将不会生效 ❞
例如下面这个场景:
代码语言:javascript复制ListView(
children: [
for (var i = 0; i < 100; i )
Container(
margin: const EdgeInsets.all(8),
color: Colors.green,
),
],
)
由于Listview中无尺寸约束,所以Container是不会展示出来的,这时候就需要使用LimitedBox。
代码语言:javascript复制ListView(
children: [
for (var i = 0; i < 100; i )
LimitedBox(
maxHeight: 100,
child: Container(
margin: const EdgeInsets.all(8),
color: Colors.green,
),
),
],
)
一句话总结LimitedBox的作用:在不受限制的环境中,为其子元素提供默认尺寸。
FittedBox
在Flutter中,Widget之间可以任意堆叠、嵌套,所以,当子Widget的尺寸与父Widget尺寸不一致时,就会产生一些奇怪的样式,FittedBox就是用来处理这种场景的。
代码语言:javascript复制Center(
child: Container(
width: 200,
height: 200,
color: Colors.red,
child: Text(
'xuyishengxuyisheng',
style: TextStyle(
fontSize: 50,
),
),
),
)
效果如图所示。
Text会因为父容器尺寸的限制而自动换行,下面我们给它加上FittedBox。
代码语言:javascript复制Center(
child: Container(
width: 200,
height: 200,
color: Colors.red,
child: FittedBox(
child: Text(
'xuyishengxuyisheng',
style: TextStyle(
fontSize: 50,
),
),
),
),
)
效果如图所示。
可以发现,FittedBox默认的fit是contain,所以内容被完整的一行显示了,与FontSize无关,这个就可以很方便的自适应修改文字大小。
当然,你还可以设置别的fit方式,详细的可以参考Flutter Dojo中的例子。fit属性是非常有用的一个属性,例如当我们设置FittedBox后,文字会在设备中自动显示为一行,但是在横竖屏切换时,Text会自动修改字体大小,来适配contain的效果,如果你想让它保存当前的文字Size,那么可以设置Fit为scaleDown,这样的话,它就会以最小尺寸来进行适配,当空间足够的时候,就不会自动放大字体大小了。
FittedBox中还可以设置alignment,从而控制剩余空间中子Widget的对齐方式。
简而言之,FittedBox就是一个让Child可以适配Parent的组件。
Flexible
准确来说,Flexible不算是Box类布局容器,但它和Box布局方式息息相关,所以这里一起说了。
Flexible通常在Column或者Row中使用,借助Flexible,可以让Column和Row中的元素根据Flex比例进行布局。
代码语言:javascript复制Column(
children: [
Flexible(
flex: 3,
child: Container(
color: Colors.cyan,
),
),
Flexible(
flex: 2,
child: Container(
color: Colors.green,
),
),
Flexible(
flex: 1,
child: Container(
color: Colors.purple,
),
),
],
)
同时,当子Widget有尺寸约束时,可以使用fit属性来控制Flex选择怎样的约束,如果是FlexFit.tight,那么Flexible将严格按照Flex布局,而忽略子Widget的尺寸约束,如果是FlexFit.loose,则会将尺寸设置为子Widget的尺寸。
OverflowBox
对于Flutter的子父Widget来说,子Widget一般都是限制于父Widget的尺寸约束之下,但如果一定要让子Widget超过父Widget的渲染区域,那么就可以通过OverflowBox来实现。
代码语言:javascript复制Container(
color: Colors.blue,
width: 200,
height: 200,
padding: const EdgeInsets.all(12.0),
child: OverflowBox(
alignment: Alignment.topLeft,
maxWidth: 300.0,
maxHeight: 500.0,
child: Container(
color: Colors.red,
width: 400.0,
height: 400.0,
),
),
)
效果如图所示。
本文原创公众号:群英传,授权转载请联系微信,授权后,请在原创发表24小时后转载。