持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情
层叠布局和Web中的绝对定位、Android中的Frame布局是相似的,子widget可以根据到父容器四个角的位置来确定本身的位置。绝对定位允许子widget堆叠(按照代码中声明的顺序)。Flutter中使用Stack和Positioned来实现绝对定位,Stack允许子widget堆叠,而Positioned可以给子widget定位(根据Stack的四个角)
Stack children:一个数组,里面可放多个Widget alignment:Alignment.topCenter//对齐方式,会对所有的子组件统一设置对齐,不灵活,一般不用
Positioned child:一个子组件 left,top,right,bottom,width,heigh://设置这些值会改变子组件的大小,位置(相对于最外层组件)
Stack
构造函数:
Stack({\
this.alignment = AlignmentDirectional.topStart,\
this.textDirection,\
this.fit = StackFit.loose,\
this.overflow = Overflow.clip,\
List<Widget> children = const <Widget>[],\
})
-
alignment:此参数决定如何去对齐没有定位(没有使用Positioned)或部分定位的子widget。所谓部分定位,在这里特指没有在某一个轴上定位:left、right为横轴,top、bottom为纵轴,只要包含某个轴上的一个定位属性就算在该轴上有定位。
-
textDirection:和Row、Wrap的textDirection功能一样,都用于决定alignment对齐的参考系即:textDirection的值为TextDirection.ltr,则alignment的start代表左,end代表右;textDirection的值为TextDirection.rtl,则alignment的start代表右,end代表左。
-
fit:此参数用于决定没有定位的子widget如何去适应Stack的大小。StackFit.loose表示使用子widget的大小,StackFit.expand表示扩伸到Stack的大小。
-
overflow:此属性决定如何显示超出Stack显示空间的子widget,值为Overflow.clip时,超出部分会被剪裁(隐藏),值为Overflow.visible 时则不会。
Stack组件可以将子组件叠加显示,根据子组件的顺利依次向上叠加,用法如下:
Stack(
children: <Widget>[
Container(
height: 200,
width: 200,
color: Colors.red,
),
Container(
height: 170,
width: 170,
color: Colors.blue,
),
Container(
height: 140,
width: 140,
color: Colors.yellow,
),
ElevatedButton(onPressed: (){}, child: Text('这个视图按钮好'))
],
)
运行效果:
从效果可以看出视图一次从左上方开始堆叠,子视图最下方的视图展示再最外层。
- fit属性
Stack未定位的子组件大小由
fit参数决定,默认值是StackFit.loose,表示子组件自己决定,StackFit.expand表示尽可能的大, fit三个可选值:
enum StackFit {
//使用子Widget 自身的大小 loose,
//使子widget与stack大小一致 expand,
//stack的父widget的布局大小约束无修改的传递给 Stack 的子Widget passthrough,
}
用法如下:
Stack(
fit: StackFit.expand,
...
)
Stack未定位的子组件的默认左上角对齐,通过alignment参数控制,用法如下:
Stack(
alignment: Alignment.center,
...
)
运行效果:
有没有注意到fit和alignment参数控制的都是未定位的子组件,那什么样的组件叫做定位的子组件?使用Positioned包裹的子组件就是定位的子组件,用法如下:
Stack(
fit: StackFit.loose,
alignment: Alignment.center,
children: <Widget>[
Container(
height: 200,
width: 200,
color: Colors.red,
),
Container(
height: 170,
width: 170,
color: Colors.blue,
),
Container(
height: 140,
width: 140,
color: Colors.yellow,
),
Positioned(
bottom: 0,
right: 0,
child: ElevatedButton(onPressed: (){}, child: Text('这个视图按钮好')))
],
)
运行效果:
如果子组件超过Stack边界由clipBehavior控制,默认是裁剪,下面设置总是显示的用法:
Stack(
clipBehavior: Clip.none,
children: <Widget>[
Container(
height: 200,
width: 200,
color: Colors.red,
),
Positioned(
left: 100,
top: 100,
height: 150,
width: 150,
child: Container(
color: Colors.green,
),
)
],
)
运行效果:
IndexedStack
IndexedStack是Stack的子类,Stack是将所有的子组件叠加显示,而IndexedStack只显示指定的子组件,用法如下:
Column(
children: [
_buildView3(),
Row(children: [
ElevatedButton(onPressed: (){
setState(() {
_index=0;
});
}, child: Icon(Icons.fastfood)),
ElevatedButton(onPressed: (){
setState(() {
_index=1;
});
}, child: Icon(Icons.cake)),
ElevatedButton(onPressed: (){
setState(() {
_index=2;
});
}, child: Icon(Icons.local_cafe))
],)
],
)
_buildView3(){
return IndexedStack(
index: _index,
children: [
Center(
child: Container(
height: 300,
width: 300,
color: Colors.yellow,
child: Icon(Icons.fastfood,color: Colors.blue,),
),
),
Center(
child: Container(
height: 300,
width: 300,
color: Colors.red,
child: Icon(Icons.cake,color: Colors.blue,),
),
),
Center(
child: Container(
height: 300,
width: 300,
color: Colors.blueGrey,
child: Icon(Icons.local_cafe,color: Colors.blue,),
),
),
],
);
}
效果(点击切换_inex,只显示第index层视图):
Positioned
Positioned用于定位Stack子组件,Positioned必须是Stack的子组件,基本用法如下:
Container(
height: 300,
width: 300,
color: Colors.amberAccent,
child: Stack(
children: <Widget>[
Positioned(
left: 10,
right: 10,
top: 10,
bottom: 10,
child: Container(color: Colors.red),
),
],
),
)
总结:
-
top、bottom、left、right四种定位属性,分别表示距离上下左右的距离。
-
用于Stack组件中。
-
left,rigit,with,3数只能设置其中2个,因为设置了其中2个,第三个已经确定了,同理top、bottom和height也只能设置其中2个。
Positioned提供便捷的构建方式,比如Positioned.fromRect、Positioned.fill等,这些便捷的构建方式万变不离其宗,只不过换了一种方式设置top、bottom、left、right四种定位属性。