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

Flutter中MaterialApp builder同时用AppBar和Drawer报错原因

Flutter报错:No Overlay widget found 原因及解决

环境信息

Flutter版本:3.11.0-11.0.pre.3

问题代码

import 'package:flutter/material.dart';

void main() async {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Test",
      theme: ThemeData(
        colorScheme: const ColorScheme.dark(),
        useMaterial3: true,
      ),
      routes: {
        '/': (context) => const Text("Home"),
        '/settings': (context) => const Text("Settings"),
      },
      builder: (context, child) => Scaffold(
        appBar: AppBar(
          title: const Text("My App"),
        ),
        drawer: const Drawer(
          child: Text("Drawer"),
        ),
        body: child,
      ),
    );
  }
}

报错信息

======== Exception caught by widgets library =======================================================
The following assertion was thrown building Tooltip("Open navigation menu", dirty, state: TooltipState#694d3(ticker inactive)):
No Overlay widget found.

Tooltip widgets require an Overlay widget ancestor within the closest LookupBoundary.
An overlay lets widgets float on top of other widget children.

To introduce an Overlay widget, you can either directly include one, or use a widget that contains an Overlay itself, such as a Navigator, WidgetApp, MaterialApp, or CupertinoApp.

The specific widget that could not find a Overlay ancestor was: Tooltip
  "Open navigation menu"
  dirty
  state: TooltipState#694d3(ticker inactive)
The ancestors of this widget were: 
  : AppBar
    dependencies: [FlexibleSpaceBarSettings, MediaQuery, _InheritedTheme, _LocalizationsScope-[GlobalKey#6ef7a], _ScrollNotificationObserverScope]
    state: _AppBarState#424ae
  : Scaffold
    dependencies: [Directionality, MediaQuery, UnmanagedRestorationScope, _InheritedTheme, _LocalizationsScope-[GlobalKey#6ef7a], _ScaffoldMessengerScope]
    state: ScaffoldState#7ef9d(tickers: tracking 2 tickers)
  : MaterialApp
    state: _MaterialAppState#13e05
  : MyApp
  ...
The relevant error-causing widget was: 
  AppBar AppBar:file:///C:/Users/me/my_app/lib/bug.dart:23:17
When the exception was thrown, this was the stack: 
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 294:49  throw_
packages/flutter/src/widgets/debug.dart 472:7                                 <fn>
packages/flutter/src/widgets/debug.dart 491:12                                debugCheckHasOverlay
packages/flutter/src/material/tooltip.dart 702:12                             build
packages/flutter/src/widgets/framework.dart 5198:27                           build
packages/flutter/src/widgets/framework.dart 5086:15                           performRebuild
packages/flutter/src/widgets/framework.dart 5251:11                           performRebuild
packages/flutter/src/widgets/framework.dart 4805:7                            rebuild
packages/flutter/src/widgets/framework.dart 5068:5                            [_firstBuild]
packages/flutter/src/widgets/framework.dart 5242:11                           [_firstBuild]
packages/flutter/src/widgets/framework.dart 5062:5                            mount
packages/flutter/src/widgets/framework.dart 3971:15                           inflateWidget
packages/flutter/src/widgets/framework.dart 3708:18                           updateChild
packages/flutter/src/widgets/framework.dart 6435:14                           mount
packages/flutter/src/widgets/framework.dart 3971:15                           inflateWidget
packages/flutter/src/widgets/framework.dart 3708:18                           updateChild
packages/flutter/src/widgets/framework.dart 6435:14                           mount
packages/flutter/src/widgets/framework.dart 3971:15                           inflateWidget
[repeats many many times]
packages/flutter/src/widgets/framework.dart 4805:7                            rebuild
packages/flutter/src/widgets/framework.dart 5068:5                            [_firstBuild]
packages/flutter/src/widgets/framework.dart 5062:5                            mount
packages/flutter/src/widgets/framework.dart 3971:15                           inflateWidget
packages/flutter/src/widgets/framework.dart 3708:18                           updateChild
packages/flutter/src/widgets/binding.dart 1253:16                             [_rebuild]
packages/flutter/src/widgets/binding.dart 1222:5                              mount
packages/flutter/src/widgets/binding.dart 1169:16                             <fn>
packages/flutter/src/widgets/framework.dart 2720:19                           buildScope
packages/flutter/src/widgets/binding.dart 1168:12                             attachToRenderTree
packages/flutter/src/widgets/binding.dart 1000:24                             attachRootWidget
packages/flutter/src/widgets/binding.dart 981:7                               <fn>
dart-sdk/lib/_internal/js_dev_runtime/private/isolate_helper.dart 48:19       internalCallback
====================================================================================================

======== Exception caught by widgets library =======================================================
The following assertion was thrown building Tooltip("Open navigation menu", dirty, state: TooltipState#694d3(ticker inactive)):
No Overlay widget found.

Tooltip widgets require an Overlay widget ancestor within the closest LookupBoundary.
An overlay lets widgets float on top of other widget children.

To introduce an Overlay widget, you can either directly include one, or use a widget that contains an Overlay itself, such as a Navigator, WidgetApp, MaterialApp, or CupertinoApp.

The specific widget that could not find a Overlay ancestor was: Tooltip
  "Open navigation menu"
  dirty
  state: TooltipState#694d3(ticker inactive)
The ancestors of this widget were: 
  : AppBar
    dependencies: [FlexibleSpaceBarSettings, MediaQuery, _InheritedTheme, _LocalizationsScope-[GlobalKey#6ef7a], _ScrollNotificationObserverScope]
    state: _AppBarState#424ae
  : Scaffold
    dependencies: [Directionality, MediaQuery, UnmanagedRestorationScope, _InheritedTheme, _LocalizationsScope-[GlobalKey#6ef7a], _ScaffoldMessengerScope]
    state: ScaffoldState#7ef9d(tickers: tracking 2 tickers)
  : MaterialApp
    state: _MaterialAppState#13e05
  : MyApp
  ...
The relevant error-causing widget was: 
  AppBar AppBar:file:///C:/Users/me/my_app/lib/bug.dart:23:17
When the exception was thrown, this was the stack: 
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 294:49      throw_
packages/flutter/src/widgets/debug.dart 472:7                                     <fn>
packages/flutter/src/widgets/debug.dart 491:12                                    debugCheckHasOverlay
packages/flutter/src/material/tooltip.dart 702:12                                 build
packages/flutter/src/widgets/framework.dart 5198:27                               build
packages/flutter/src/widgets/framework.dart 5086:15                               performRebuild
packages/flutter/src/widgets/framework.dart 5251:11                               performRebuild
packages/flutter/src/widgets/framework.dart 4805:7                                rebuild
packages/flutter/src/widgets/framework.dart 2780:18                               buildScope
packages/flutter/src/widgets/binding.dart 916:9                                   drawFrame
packages/flutter/src/rendering/binding.dart 358:5                                 [_handlePersistentFrameCallback]
packages/flutter/src/scheduler/binding.dart 1290:15                               [_invokeFrameCallback]
packages/flutter/src/scheduler/binding.dart 1220:9                                handleDrawFrame
packages/flutter/src/scheduler/binding.dart 1078:5                                [_handleDrawFrame]
lib/_engine/engine/platform_dispatcher.dart 1245:13                               invoke
lib/_engine/engine/platform_dispatcher.dart 247:5                                 invokeOnDrawFrame
lib/_engine/engine/initialization.dart 189:45                                     <fn>
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 570:37  _checkAndCall
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 575:39  dcall
====================================================================================================

核心疑问

当移除AppBar或Drawer其中一个时,不会抛出错误,请问该报错的原因是什么?


原因分析

  • 层级搞反了:MaterialApp内部会自动创建Navigator,而Navigator会提供一个Overlay——这是用来承载悬浮组件(比如Tooltip、Dialog)的容器。但你把Scaffold写在了MaterialApp的builder参数里,导致Scaffold的层级比Navigator还高,它内部的组件向上查找Overlay时,根本找不到Navigator提供的那个。
  • Tooltip触发了报错:当同时存在AppBar和Drawer时,AppBar会自动生成一个打开抽屉的菜单按钮,这个按钮默认带有Tooltip提示框。Tooltip必须依赖Overlay才能显示悬浮提示,现在找不到合法的Overlay祖先,直接抛出异常。
  • 移除一个就正常的原因:要么移除Drawer,AppBar不会生成那个带Tooltip的按钮;要么移除AppBar,干脆没了触发报错的组件,自然就不会报错了。

解决办法

方案一:规范路由结构(推荐)

把Scaffold放到路由对应的页面Widget里,让它处于Navigator的Overlay层级之下:

routes: {
  '/': (context) => Scaffold(
        appBar: AppBar(title: const Text("My App")),
        drawer: const Drawer(child: Text("Drawer")),
        body: const Text("Home"),
      ),
  '/settings': (context) => const Text("Settings"),
},

方案二:手动添加Overlay(适合全局统一布局)

如果确实需要全局共用一个Scaffold结构,可以在builder中手动嵌套Overlay,让Tooltip能找到它:

builder: (context, child) => Overlay(
  initialEntries: [
    OverlayEntry(
      builder: (context) => Scaffold(
        appBar: AppBar(title: const Text("My App")),
        drawer: const Drawer(child: Text("Drawer")),
        body: child,
      ),
    ),
  ],
),

内容的提问来源于stack exchange,提问作者Michel Jung

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 16:37:06