Flutter 3.11.0-11.0.pre.3
Given this Code:
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,
),
);
}
}
Why am I getting:
======== 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
====================================================================================================
Interestingly, when I remove either, appBar
or drawer
, no error is thrown.
2
Answers
The builder property in MaterialApp is to wrap the Navigator it creates with a widget you want to use:
A
Drawer
uses inside aTooltip
so it will throw as long as you use it like this. If you really want to have an scaffold and then a navigator you need to create your own Navigator or pass the globalKey of the scaffold to your appbar and do the open drawer logic yourself:Simply put, The reason is that the context of the builder and the context of the MaterialApp are different.
The context of the builder cannot be delivered to the MaterialApp.
For a specific reason,
The widget at the top of Flutter is the Overlay widget, which is caused by the absence of an Overlay widget. To be exact, the Tootip widget in Appbar did not find Overlay.
(MaterialApp provides Overlay by default. That’s why multiple widgets inside Scaffold must be located under the MaterialApp to enable Overlay)
For example, to display Tooltip in the Action button of the AppBar, or to display SnackBar using the showSnackBar function of Scaffold, you need Overlay.
(Tooltip and SnackBar work in the context of the Overlay widget)
These widgets have the MaterialApp at the top, so you can access Overlay. Therefore, Scaffold must be located as a direct child of MaterialApp to access Overlay.
Then why can’t context of the builder be delivered to the MaterialApp?
That’s because the context is limited to the location where the ‘range’ calls the builder function. This is based on a design decision that allows widgets created within a builder function to know only information about the widget that calls the builder function.
Therefore, the builder function cannot refer to a widget tree higher than where the builder is called.
Because the MaterialApp calls the builder function, the builder function cannot access widgets of MaterialApp. In other words, widgets inside the builder function cannot access widgets of MaterialApp
So, If you create Scaffolds directly from the builder properties of MaterialApp, Scaffolds and their subwidgets cannot access the BuildContext provided by MaterialApp. This will result in the loss of access to everything, including Overlay, provided by MaterialApp.