APP开发经常要遇到的开发场景
有时候我们在开发APP的时候会遇到下面这些需求:
在现有页面上添加浮动的悬浮按钮、气泡或菜单。
实现全局的通知或提示弹窗。
创建自定义的导航栏、底部导航或标签栏。
构建模态对话框或底部弹出菜单。
在屏幕上展示悬浮窗,比如 Flutter 版本的 Toast,任意位置的 PopWindow 等等。
自定义Toast。
在页面顶部悬浮某个widget。
等等。
这些场景都有一个共同特点,需要在当前UI上悬浮显示特定的UI。要用flutter来实现这些效果就要引出今天要学习的Overlay组件。
Overlay 的介绍
当需要在 Flutter 应用中在现有 UI 层上添加新的视图或交互时,可以使用 Overlay 组件。Overlay 允许将一个或多个小部件(称为 OverlayEntry)叠加在应用的现有 UI 上。
Overlay包括两个基本组件:OverlayState和OverlayEntry。OverlayState管理所有OverlayEntry,OverlayEntry定义覆盖层的内容。
Overlay的使用规则
创建一个 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按钮后的效果图如下: