有时候我们在开发APP的时候会遇到下面这些需求:
在现有页面上添加浮动的悬浮按钮、气泡或菜单。
实现全局的通知或提示弹窗。
创建自定义的导航栏、底部导航或标签栏。
构建模态对话框或底部弹出菜单。
在屏幕上展示悬浮窗,比如 Flutter 版本的 Toast,任意位置的 PopWindow 等等。
自定义Toast。
在页面顶部悬浮某个widget。
等等。
这些场景都有一个共同特点,需要在当前UI上悬浮显示特定的UI。要用flutter来实现这些效果就要引出今天要学习的Overlay组件。
当需要在 Flutter 应用中在现有 UI 层上添加新的视图或交互时,可以使用 Overlay 组件。Overlay 允许将一个或多个小部件(称为 OverlayEntry)叠加在应用的现有 UI 上。
Overlay包括两个基本组件:OverlayState和OverlayEntry。OverlayState管理所有OverlayEntry,OverlayEntry定义覆盖层的内容。
创建一个 Overlay 对象,通常使用 Overlay.of(context) 方法获取当前上下文中的 Overlay 对象。
创建一个或多个 OverlayEntry 对象,这些对象将成为 Overlay 的子项。
将 OverlayEntry 添加到 Overlay 中,通常使用 OverlayEntry 的 insert 或 add 方法。
当需要显示或隐藏叠加层时,调用 OverlayEntry 的 markNeedsBuild 方法,并在 build 方法中定义要显示的小部件。
可选:通过调整 OverlayEntry 的位置、大小和布局参数来控制叠加层的位置和样式。
下面通过一个简单的例子来说明:例子要实现点击一个按钮会打开Overlay显示一个FloatingActionButton。
import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: Text('Flutter Overlay Example'), ), body: Center( child: ElevatedButton( child: Text('Open Overlay'), onPressed: () { showFloatingButtonOverlay(context); }, ), ), ), ); } } void showFloatingButtonOverlay(BuildContext context) { OverlayState? overlayState = Overlay.of(context); late OverlayEntry overlayEntry; // 创建 OverlayEntry overlayEntry = OverlayEntry( builder: (BuildContext context) { return Positioned( top: 100, right: 16, child: FloatingActionButton( onPressed: () { // 悬浮按钮被点击 print('Floating Button Clicked'); overlayEntry.remove(); // 移除 OverlayEntry }, child: Icon(Icons.add), ), ); }, ); // 将 OverlayEntry 添加到 Overlay 中 overlayState?.insert(overlayEntry); }
本来想直接贴正确的代码的,但是觉得这个错误对初学者来说很容易犯,故单独列出来。
报错No Overlay widget found
点击Open Overlay按钮报错No Overlay widget found。如下图
该错误提示是因为在使用 Overlay.of(context) 方法时,找不到可用的 Overlay 对象。
确保按钮所在的 BuildContext 对象正确。在上述示例中,按钮的 onPressed 回调中使用的 BuildContext 应该是 Scaffold 的上下文,确保按钮在正确的上下文中定义和使用。
确保 Overlay 被正确地放置在应用的组件树中。在上述示例中,Overlay 组件应该在 MaterialApp 或 WidgetsApp 的下方,以确保它们在正确的层次结构中。
import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: OverlayExample(), // 使用 OverlayExample 作为主页 ); } } class OverlayExample extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Flutter Overlay Example'), ), body: Center( child: ElevatedButton( child: Text('Open Overlay'), onPressed: () { showFloatingButtonOverlay(context); }, ), ), ); } } void showFloatingButtonOverlay(BuildContext context) { OverlayState? overlayState = Overlay.of(context); late OverlayEntry overlayEntry; // 创建 OverlayEntry overlayEntry = OverlayEntry( builder: (BuildContext context) { return Positioned( top: 100, right: 16, child: FloatingActionButton( onPressed: () { // 悬浮按钮被点击 print('Floating Button Clicked'); overlayEntry.remove(); // 移除 OverlayEntry }, child: Icon(Icons.add), ), ); }, ); // 将 OverlayEntry 添加到 Overlay 中 overlayState?.insert(overlayEntry); }
运行起来的效果如图:
点击Open Overlay按钮后的效果图如下:
Copyright © 2023 leiyu.cn. All Rights Reserved. 磊宇云计算 版权所有 许可证编号:B1-20233142/B2-20230630 山东磊宇云计算有限公司 鲁ICP备2020045424号
磊宇云计算致力于以最 “绿色节能” 的方式,让每一位上云的客户成为全球绿色节能和降低碳排放的贡献者