Flutter入门笔记系列文章部分内容来源于《Flutter 实战》,如有侵权请联系删除!
层叠布局和Web中的绝对定位、Android中的Frame布局是相似的,子组件可以根据距父容器四个角的位置来确定自身的位置。绝对定位允许子组件堆叠起来(按照代码中声明的顺序)。
Flutter中使用Stack和Positioned这两个组件来配合实现绝对定位。Stack允许子组件堆叠,而Positioned用于根据Stack的四个角来确定子组件的位置。
Stack
Stack({
Key key,
this.alignment = AlignmentDirectional.topStart,
this.textDirection,
this.fit = StackFit.loose,
this.overflow = Overflow.clip,
List children = const [],
})
- alignment:此参数决定如何去对齐没有定位(没有使用Positioned)或部分定位的子组件。所谓部分定位,在这里特指没有在某一个轴上定位:left、right为横轴,top、bottom为纵轴,只要包含某个轴上的一个定位属性就算在该轴上有定位。
- textDirection:和Row、Wrap的textDirection功能一样,都用于确定alignment对齐的参考系,即:textDirection的值为TextDirection.ltr,则alignment的start代表左,end代表右,即从左往右的顺序;textDirection的值为TextDirection.rtl,则alignment的start代表右,end代表左,即从右往左的顺序。
- fit:此参数用于确定没有定位的子组件如何去适应Stack的大小。StackFit.loose表示使用子组件的大小,StackFit.expand表示扩伸到Stack的大小。
- overflow:此属性决定如何显示超出Stack显示空间的子组件;值为Overflow.clip时,超出部分会被剪裁(隐藏),值为Overflow.visible 时则不会。
Positioned
const Positioned({
Key key,
this.left,
this.top,
this.right,
this.bottom,
this.width,
this.height,
@required Widget child,
})
left、top 、right、 bottom分别代表离Stack左、上、右、底四边的距离。width和height用于指定需要定位元素的宽度和高度。注意,Positioned的width、height 和其它地方的意义稍微有点区别,此处用于配合left、top 、right、 bottom来定位组件,举个例子,在水平方向时,你只能指定left、right、width三个属性中的两个,如指定left和width后,right会自动算出(left+width),如果同时指定三个属性则会报错,垂直方向同理。
介绍完Stack和Positioned,可以开始尝试着写个小例子:
body: Stack(
alignment: Alignment.center,
children: [
Positioned(
left: 0,
top: 0,
child: RaisedButton(
onPressed: () {},
child: Text("AAA"),
),
),
Positioned(
left: 50,
child: RaisedButton(
onPressed: () {},
child: Text("BBBB"),
),
),
],
)
运行效果
按钮AAA在横纵轴上都有定位,所以不受alignment属性的影响,显示在(0, 0)位置;但是按钮BBB只定位了是横轴left,所以按钮BBB纵轴上的对齐方式还是由alignment决定,因此在纵轴上居中显示。
如果我们添加一个按钮CCC,并且不设置任何定位,我们看看会发生什么。
Positioned(
child: RaisedButton(
onPressed: () {},
child: Text("CCC"),
),
),
//下面代码省略
按钮AAA
按钮BBB
运行效果
因为按钮CCC没有定位,因此fit参数会确定它如何去适应Stack的大小。fit参数的默认值为StackFit.loose,所以Stack会使用按钮CCC的大小。也就是说只要将fit参数修改为StackFit.expand,Stack就会充满屏幕,看看运行效果是否真是如此!
果然按钮CCC充满了整个屏幕,是不是感觉还漏讲了什么?没错overflow属性还未被提及过,如果我没记错它应该是在本系列第一次出场吧,那就专门介绍一下它吧!
从本文第二张效果图可以看到,按钮B只显示了一部分,说明有一部分被裁减掉了,这也正好验证了overflow参数的默认值确实是Overflow.clip,我们把值改为Overflow.visible看看会是什么样的效果。
body: Stack(
alignment: Alignment.center,
overflow: Overflow.visible, //超出部分展示出来
children: [
Positioned(
child: RaisedButton(
onPressed: () {},
child: Text("CCC"),
),
),
Positioned(
left: 0,
top: 0,
child: RaisedButton(
onPressed: () {},
child: Text("AAA"),
),
),
Positioned(
left: 50,
child: RaisedButton(
onPressed: () {},
child: Text("BBBB"),
),
),
],
),
运行效果
可以看到超出部分正常显示出来了。