前言:
这是我参与8月更文挑战的第 19 天,活动详情查看:8月更文挑战。为应掘金的八月更文挑战
,我准备在本月挑选 31
个以前没有介绍过的组件,进行全面分析和属性介绍。这些文章将来会作为 Flutter 组件集录
的重要素材。希望可以坚持下去,你的支持将是我最大的动力~
一、 认识 Flexible 组件
从源码中可以看出 Flexible
组件只能用于 Row
、Column
或 Flex
组件中。我们知道 Row
和Column
的本质也是 Flex
组件,在很久之前写过 Flex
的使用文章。今天来看一下 Flex
组件的御用
周边组件。Flexible
的作用是:使子组件可以灵活地填充主轴的可用空间
。
1.Flexible 基本信息
Flexible
继承自 ParentDataWidget<FlexParentData>
,这个类型的父组件可能大家都没见过,毕竟我们很少自定义 ParentDataWidget
类型的组件。Flexible
构造中必须传入 child 组件。另外还有两个参数:int
型的 flex
,和 FlexFit
枚举型的 fit
。
可以说类的定义还是比较简单的,下面一起看一下该组件的使用,及两个属性的作用。
2.Flexible 的使用
我们用如下的 Row
组件进行测试,外框是 Row
组件的区域,目前里面只有一个头像,占位为深蓝色区域。前面提到:Flexible
可使子组件可以灵活地填充主轴中的可用空间
。那么这里的可以空间就是 Row
除深蓝色区域。
class FlexibleDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 200,
height: 54,
color: Colors.grey.withAlpha(11),
child: Row(
children:[
buildHead(),
],
),
);
}
Widget buildHead(){
return Padding(
padding: const EdgeInsets.all( 8.0),
child: Image.asset('assets/images/icon_head.png',width: 40,height: 40,),
);
}
}
现在做个小测试,在 Row
里添加一个蓝色的 Container
,那么会如何显示。Container
组件的占位又会是怎样呢?
Row(
children:[
buildHead(),
Container(
color: Colors.blueAccent,
),
]
)
可以看出在为 54
的 Row
中 Container
默认的约束为 [w(0,0) - h(0,54)]
。再加上 Container
在父区域内延展的特性,尺寸为 Size(0,54)
,也就是说它不可见。
当然,我们可以通过指定宽度来修改区域约束,让 Container
显示出来。但有个问题:如何让 Container
填充剩余的空间呢?
虽然我们可以通过计算剩余尺寸来设置 Container
的宽,但是这个计算过程比较麻烦,特别是 Row 里子组件非常多或不固定,用算的自然比较费劲。其实这些 Flutter 内部已经帮你做了,并暴露一个 Flexible
组件来给你用。我们只需要简单地套一个 Flexible
即可。
Row(
children:[
buildHead(),
Flexible( //<--- 使用 Flexible
child: Container(
color: Colors.blueAccent,
),
),
],
)
可以看出加上 Flexible
组件后,约束变成了 [w(0,144) - h(0,54)]
,其中 144
是框架内部帮我们计算出来的。我们只需要使用 Flexible
组件,不必考虑计算的细节,是不是很妙。
3.Flexible 的 flex 属性作用
如果只有一个子组件套 Flexible
,那么 flex
属性设成什么都是一样的效果。当有多个 Flexible
组件时,会根据 flex
值 瓜分剩余空间
,如下是 蓝 3 红 1
的效果。
Row(
children:[
buildHead(),
Flexible(
flex:3,
child: Container(
color: Colors.blueAccent,
),
),
Flexible(
flex: 1,
child: Container(
color: Colors.red,
),
)
],
),
也就是蓝色占据剩余宽度 (3/(3+1))
的百分比,剩余宽是 144
,从树中可以看出,第一个 Container
的宽确实是 108
。这样多个 Flexible
组件时,根据 flex
属性我们可以确定该组件在剩余空间的占比。
4.Flexible 的 fit 属性作用
fit
是一个 FlexFit
型的枚举,只有两个元素 tight
和 loss
,所以并不是很难。默认下是 loss
。
enum FlexFit {
tight,
loose,
}
那 tight
和 loss
有什么作用呢?我们通过之前的例子再看一下:如果 Flexible
包裹的子组件有固定的尺寸,默认情况下 loss
是无法使其区域延展的,甚至 Flexible
本身的尺寸也不会扩展。
Row(
children:[
buildHead(),
Flexible(
fit: FlexFit.loose,
child: Container(
width: 40,
color: Colors.blueAccent,
),
),
],
),
当为 tight
时,Flexible
会强制 延展
。这就是两者最大的区别。
Row(
children:[
buildHead(),
Flexible(
fit: FlexFit.tight,
child: Container(
width: 40,
color: Colors.blueAccent,
),
),
],
),
可能 Container
自身的延展性上面的例子体现并不明显。可以通过一个固定尺寸的 Icon
来说明一下:如下左侧是 loose
,右侧是 tight
。只要记住 tight
会强制延展自身区域即可。
二、Expanded 组件的实现
Expanded
的实现非常非常简单,下面是它的全部代码。它就是继承自 Flexible
组件,将 fit
值固定为 tight
而已,所以说 Expanded
就是一个强制延展的 Flexible
组件。
两者在使用上并没有什么区别,由于 Flexible
可以设置 fit
值,所以用途要比 Expanded
广泛。而强制延展的场景使用 Expanded
组件语义更好,而且简单一点。
三、Spacer 组件的实现
Spacer
的实现也非常简单,下面是它的全部代码。它是一个 StatelessWidget
,内部依赖 Spacer
组件实现功能,特点是:它不能设置子组件,本身作为空白占位使用。
总的来说 Spacer
和 Expanded
的功能都基于 Flexible
组件实现。了解了 Flexible
组件的使用,就可以一通百通。那本文到这里就结束了,谢谢观看,明天见~