Overlay
用于在屏幕上显示浮层的组件
定义及作用
- 用于在屏幕上显示浮层的组件。
- 创建弹出窗口、提示框、菜单、对话框等。
源码分析
/// Overlay的设计思路
class Overlay extends StatefulWidget
//可以看出Overlay是一个有状态的widget,直接看对应的OverlayState里面的实现。
final List<OverlayEntry> _entries = <OverlayEntry>[];
//OverlayState里面维护OverlayEntry的列表,那么OverlayEntry是什么?
/// 在OverlayEntry注释里有这样一段:
Because an [Overlay] uses a [Stack] layout, overlay entries can use [Positioned] and [AnimatedPositioned] to position themselves within the overlay.
//这句话可以理解为Overlay包含一个Stack布局,每个浮层都是一个Positioned widget,可以添加到Stack中。
又因为Stack是可以覆盖的,所以就能做出浮窗等效果。
/// 至此已经明白了一个基本思路:OverlayEntry是浮窗的UI,而OverlayState通过维护OverlayEntry来显示对应的UI。那么怎么绘制的呢?
Widget build(BuildContext context) {
...
for (int i = _entries.length - 1; i >= 0; i -= 1) {
...
children.add(_OverlayEntryWidget(
key: entry._key,
entry: entry,
));
// 至此,在build里,通过_OverlayEntryWidget这个实际绘制UI的widget绘制,然后add给children,children在给真正绘制的UI的地方(这就不继续跟下去了,这里着重发现Overlay的设计思路)
/// 总结:OverlayEntry是浮窗的UI,而OverlayState在build遍历OverlayEntry的列表来绘制每一个OverlayEntry。
使用举例
- 基于上面总结原理,使用Overlay就需要在OverlayEntry里绘制UI,然后add给OverlayState。
- 如下(步骤在注释上):
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Column(
children: [
ElevatedButton(
onPressed: () => btn1(context),
child: const Text("btn1"),
),
],
),
),
);
}
void btn1(BuildContext context) {
/// 步骤1:绘制OverlayEntry的UI
OverlayEntry? overlayEntry;
overlayEntry = OverlayEntry(builder: (context) {
return Positioned(
// 指定位置
left: 0,
top: 100,
child: GestureDetector(
// 点击删除
onTap: () {
overlayEntry?.remove();
},
// 背景随机色
child: Container(
width: 100,
height: 100,
color: Colors.red,
child: const Center(
// 提示文字
child: Text(
"这是一个 overlay 浮层, 点击关闭",
style: TextStyle(
color: Colors.white,
fontSize: 10,
decoration: TextDecoration.none,
),
),
),
),
),
);
});
/// 步骤2:把OverlayEntry的添加给overlayState。overlayState自己就会去setState展示
OverlayState? overlayState = Overlay.of(context);
overlayState.insert(overlayEntry);
/// 步骤2:实际使用时通过Overlay.of(context)获得OverlayState要在dispose()时销毁
}
}
补充
OverlayEntry
- 构造函数及描述参数作用:
OverlayEntry({
required this.builder, // 绘制UI
bool opaque = false, // 是否不透明的,设置为true,就会让当前屏幕除了UI,都被遮盖,因为不透明嘛
bool maintainState = false, //绘制的UI里如果没有用StatefulWidget,就设置为false,如果用了并且希望接收到外层的setState就设置为true
})
OverlayState
- 前面说了OverlayState是维护OverlayEntry的。而实际开发中弹框也不会弹多个浮层令人厌烦,所以OverlayState的维护(增删排序等)功能,基本无须过多了解。