skip to Main Content

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


  1. The builder property in MaterialApp is to wrap the Navigator it creates with a widget you want to use:

    A builder for inserting widgets above the Navigator or – when the
    WidgetsApp.router constructor is used – above the Router but below the
    other widgets created by the WidgetsApp widget, or for replacing the
    Navigator/Router entirely.

    For example, from the BuildContext passed to this method, the
    Directionality, Localizations, DefaultTextStyle, MediaQuery, etc, are
    all available. They can also be overridden in a way that impacts all
    the routes in the Navigator or Router.

    A Drawer uses inside a Tooltip 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:

    MaterialApp(
      title: "Test",
      theme: ThemeData(
        colorScheme: const ColorScheme.dark(),
        useMaterial3: true,
      ),
      routes: {
        '/': (context) => const Text("Home"),
        '/settings': (context) => const Text("Settings"),
      },
      builder: (context, child) => OuterScaffold(child: child),
    );
    
    class OuterScaffold extends StatefulWidget {
      final Widget? child;
      const OuterScaffold({super.key, this.child});
    
      @override
      State<OuterScaffold> createState() => _OuterScaffoldState();
    }
    
    class _OuterScaffoldState extends State<OuterScaffold> {
      final GlobalKey<ScaffoldState> _state = GlobalKey<ScaffoldState>();
      
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          key: _state,
          appBar: AppBar(
            leading: IconButton(
              icon: const Icon(Icons.menu),
              iconSize: 24.0,
              onPressed: () => _state.currentState?.openDrawer(),
            ),
            title: const Text("My App"),
          ),
          drawer: const Drawer(
            child: Text("Drawer"),
          ),
          body: widget.child,
        );
      }
    }
    
    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search