Stack
在 Flutter 中,Stack 是一个用于叠加多个小部件的布局小部件。它允许你将多个小部件重叠放置,通过控制每个小部件的位置和大小,你可以创建出复杂的布局效果,如徽章图标、对话框、自定义形状等
Stack({
Key key,
this.alignment = AlignmentDirectional.topStart,
this.textDirection,
this.fit = StackFit.loose,
this.overflow = Overflow.clip,
List<Widget> children = const <Widget>[],
})
因为Stack中的child是重叠关系,所以需要对child进行定位,根据定位的不同Stack中的child可以分为两种类型,分别是positioned和non-positioned。
所谓positioned,是指child widget被包装在Positioned中。Positioned是专门用来定位Stack中的child位置的一个widget。所以Positioned必须用在Stack中,那么这个对象就是一个Stack中的positioned对象。Positioned中除了封装的child之外,还有6个属性,如下所示:
const Positioned({
Key? key,
this.left,
this.top,
this.right,
this.bottom,
this.width,
this.height,
required Widget child,
})
这六个属性分别是left,top,right,bottom,width和height。其中left,top,right,bottom分别表示到左,顶,右,底的距离,这个距离是相对stack来说的。而width和height则表示的是Positioned的宽度和高度。
事实上,使用left和right可以定义出width,使用top和bottom可以定义出height。
如果在一个轴方向的三个值都不存在,那么会使用Stack.alignment来定位子元素。
如果六个值都不存在,那么这个child就是一个non-positioned的child。
对于non-positioned的child,是通过Stack的alignment来进行布局的
属性
-
Stack常用属性
-
children:子视图
-
alignment:子视图的对齐方式
- topLeft:顶部左对齐
- topCenter:顶部居中对齐
- topRight:顶部右对齐
- centerLeft:中间左对齐
- center:中间对齐
- centerRight:中间右对齐
- bottomLeft:底部左对齐
- bottomCenter:底部居中对齐
- bottomRight:底部右对齐
-
clipBehavior,裁剪,可能会影响性能
- Clip.hardEdge: Stack默认为此选项
- Clip.antiAlias: 平滑裁剪
- Clip.antiAliasWithSaveLayer
- Clip.none: 不需要裁剪
-
fit:子视图填充方式
- StackFit.loose: 使用子组件的大小
- StackFit.expand: 充满父视图的区域
- StackFit.passthrough: 透传,使用Stack的父视图的布局方式
-
textDirection
- TextDirection.ltr
- TextDirection.rtl
-
使用
no-positioned使用
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: [
const CircleAvatar(
backgroundImage: AssetImage('images/head.jpg'),
radius: 100,
),
Container(
decoration: const BoxDecoration(
color: Colors.green,
),
child: const Text(
'编辑',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
],
);
positioned使用
class PositionScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Postion Title"),
),
body: Stack(
children: <Widget>[
Positioned(
top: 100.0,
child: Container(
color: Colors.blue,
child: Text("第一个组件"),
),
),
Positioned(
top: 200,
right: 100,
child: Container(
color: Colors.yellow,
child: Text("第二个组件"),
),
),
Positioned(
left: 100.0,
child: Container(
color: Colors.red,
child: Text("第三个组件"),
),
),
],
),
);
}
}
这个例子的效果就是
- 第一个组件距离顶部Stack 有100的间距
- 第二个组件距离顶部200,距离右边100间距
- 第三个组件距离左边100间距
IndexStack
IndexedStack是Flutter中的一个布局组件,用于在多个子组件之间切换,并且只显示当前子组件。下面是关于使用IndexedStack的详细说明:
IndexedStack(
index: 0, // 初始显示子组件的下标
children: [
// 子组件列表
Container(color: Colors.blue),
Container(color: Colors.green),
Container(color: Colors.red),
],
)
属性解析:
index:代表当前显示的子组件的下标。比如上面设置为0,就是显示第1个子组件。如果改成1,则是显示第2个子组件。 children:是一个列表,其中包含IndexedStack要显示的所有子组件。
实现原理
IndexedStack的实现原理其实很简单,只是在显示某个子组件时,将其他的子组件隐藏了。要实现这个功能,Flutter内部是通过一个Stack和多个Offstage实现的。
Stack:是一个无限制大小的布局模型,它的子组件可以叠放在一起。IndexedStack实际上就是一个Stack。 Offstage:用于将一个组件隐藏,可以通过将其offstage属性设置为true来实现。 IndexedStack会将除了当前显示的子组件以外的所有子组件的offstage属性都设置为true,这样就实现了不显示这些子组件的目的。
注意事项:
IndexedStack会同时加载所有的子组件,所以如果子组件比较多或者占用内存较大,这种方式可能会对性能产生影响。 当需要动态切换子组件时,可以通过修改index来实现,比如将index设置为一个变量,然后在需要切换时,修改这个变量即可