Flutter调用Overlay.of(context)返回null,插入全局Overlay报错如何解决?
错误原因
Overlay.of(context)返回null是因为你传入的context来自MaterialApp的builder参数,这个层级在Flutter组件树中位于MaterialApp内部的导航器(Navigator)之上,而Overlay是导航器内部才初始化的组件,从当前context向上查找无法找到Overlay实例。- 原有写法会在每次MyApp触发build时重复插入OverlayEntry,后续会出现重复悬浮组件的问题。
修复方案
直接用你已经声明的全局导航器keyAppNavigator.navigatorKey来获取导航器对应的context,这个context所在层级一定能找到Overlay实例,同时新增插入标记避免重复插入,建议将MyApp改为StatefulWidget管理状态:
// 改为StatefulWidget class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { // 标记Overlay是否已插入 bool _isOverlayInserted = false; // 可选:保存OverlayEntry方便后续移除 OverlayEntry? _overlayEntry; @override Widget build(BuildContext context) { final theme = Theme.of(context); return MaterialApp( color: Colors.white, title: 'Gratitude', navigatorKey: AppNavigator.navigatorKey, onGenerateRoute: AppNavigator.onGenerateRoute, theme: ThemeData( fontFamily: AppFonts.POPPINS, textTheme: theme.textTheme.apply( fontFamily: AppFonts.POPPINS, displayColor: AppColors.TEXT_COLOR, )), builder: (context, child) { final data = MediaQuery.of(context); final smallestSize = min(data.size.width, data.size.height); final textScaleFactor = min(smallestSize / AppConstants.designScreenSize.width, 1.0); if (!_isOverlayInserted) { WidgetsBinding.instance.addPostFrameCallback((_) => _insertOverlay()); _isOverlayInserted = true; } return MediaQuery( data: data.copyWith(textScaleFactor: textScaleFactor), child: child ?? const SizedBox.shrink(), ); }); } void _insertOverlay() { final navContext = AppNavigator.navigatorKey.currentContext; if (navContext == null) return; _overlayEntry = OverlayEntry(builder: (context) { final size = MediaQuery.of(context).size; print(size.width); return Positioned( width: 56, height: 56, top: size.height - 72, left: size.width - 72, child: Material( color: Colors.transparent, child: GestureDetector( onTap: () => print('ON TAP OVERLAY!'), child: Container( decoration: const BoxDecoration(shape: BoxShape.circle, color: Colors.redAccent), ), ), ), ); }); Overlay.of(navContext)?.insert(_overlayEntry!); } }
补充说明
- 这个方式插入的Overlay挂载在全局导航器上,路由切换的时候不会被移除,符合你全局显示的需求。
- 如果后续需要移除Overlay,直接调用
_overlayEntry?.remove()即可。
内容的提问来源于stack exchange,提问作者Chandru
相关产品推荐
相关产品推荐

