You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.18 02:36:04