skip to Main Content

I want to show an overlay on the whole app so I tried to insert an overlay entry on the context of MaterialApp (root widget) but the problem is I’m getting the null value on invoking the following method :

Overlay.of(context);
GetMaterialApp.router(
          debugShowCheckedModeBanner: false,
          theme: AppTheme.lightTheme,
          scaffoldMessengerKey: Keys.scaffold,
          scrollBehavior: MyCustomScrollBehavior(),
          routeInformationParser: WebRoutes.goRouter.routeInformationParser,
          routerDelegate: WebRoutes.goRouter.routerDelegate,
          routeInformationProvider: WebRoutes.goRouter.routeInformationProvider,
          builder: (context, child) {

          WidgetsBinding.instance.addPostFrameCallback((_){
              addOverlay(context);
            });
           
            return child;

}

void addOverlay(BuildContext context) {
  print(Overlay.of(context));

  return Overlay.of(context)?.insert(OverlayEntry(
    builder: (context) {
      return SomeWidget();
    },
  ));
}

Is there any way to get the state of overlay using the context of this root widget as I want to show the overlay globally.

Thanks alot, I really appreciate that If someone helps me.

3

Answers


  1. import 'package:flutter/material.dart';
    import 'package:get/get_navigation/src/root/get_material_app.dart';
    import 'package:go_router/go_router.dart';
    
    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
    
      runApp(App2());
    }
    
    class App2 extends StatelessWidget {
      App2({super.key});
      final _router = GoRouter(
        routes: [
          GoRoute(
            path: '/',
            builder: (context, state) => const OverlayWrapper(),
          ),
        ],
      );
    
      @override
      Widget build(BuildContext context) {
        return GetMaterialApp.router(
          routeInformationParser: _router.routeInformationParser,
          routerDelegate: _router.routerDelegate,
          routeInformationProvider: _router.routeInformationProvider,
        );
      }
    }
    
    class OverlayWrapper extends StatefulWidget {
      const OverlayWrapper({Key? key}) : super(key: key);
    
      @override
      State<OverlayWrapper> createState() => _OverlayWrapperState();
    }
    
    class _OverlayWrapperState extends State<OverlayWrapper> {
      @override
      void initState() {
        super.initState();
      }
    
      showOverLay() {
        OverlayEntry overlayEntry = OverlayEntry(
          builder: (context) => Container(
            color: Colors.red,
            child: const Text('data'),
          ),
        );
        Overlay.of(context).insert(overlayEntry);
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: ElevatedButton(
              onPressed: () {
                showOverLay();
              },
              child: const Text(
                'ShowOverlay',
                style: TextStyle(),
              ),
            ),
          ),
        );
      }
    }
    
    Login or Signup to reply.
  2. You can achieve that by create a class responsible to display/remove the overlay, this class need receive a BuildContext when creating to be able to create an instance of Overlay.

    Basically what you need to do are:

    1. Create a class OverlayScreen that build the OverlayState && OverlayEntry (in this case the OverylayEntry will be a list of OverlayEntry since we might have more than one Overlay on the screen so we can remove all of them at once).

    2. Create an instance of this class earlier in your app (e.g MyApp). In your case you’ll need to call this inside Material.router…builder param.

    3. Access this overlayScreen in your HomePage to display|removeAll overlays

    Lets create our OverlayScreen

    import 'package:flutter/material.dart';
    
    class OverlayScreen {
      /// Create an Overlay on the screen
      /// Declared [overlayEntrys] as List<OverlayEntry> because we might have
      /// more than one Overlay on the screen, so we keep it on a list and remove all at once
      BuildContext _context;
      OverlayState? overlayState;
      List<OverlayEntry>? overlayEntrys;
    
      void closeAll() {
        for (final overlay in overlayEntrys ?? <OverlayEntry>[]) {
          overlay.remove();
        }
        overlayEntrys?.clear();
      }
    
      void show() {
        overlayEntrys?.add(
          OverlayEntry(
            builder: (context) {
              return _buildOverlayWidget();
            },
          ),
        );
    
        overlayState?.insert(overlayEntrys!.last);
      }
    
      OverlayScreen._create(this._context) {
        overlayState = Overlay.of(_context);
        overlayEntrys = [];
      }
    
      factory OverlayScreen.of(BuildContext context) {
        return OverlayScreen._create(context);
      }
    
      Widget _buildOverlayWidget() {
        return Positioned(
          top: 20,
          left: 20,
          right: 20,
          child: Container(
            width: 300,
            color: Colors.black,
            height: 300,
            child: const Text("MY CHAT"),
          ),
        );
      }
    }
    
    

    Now lets create an instance on MyApp

    
    // Need to have it global to be able to access everywhere
    OverlayScreen? overlayScreen;
    
    void main() {
      runApp(
        const MyApp(),
      );
    }
    
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: const HomePage(),
          builder: (context, child) {
            return Overlay(
              initialEntries: [
                OverlayEntry(
                  builder: (context) {
    // Create an instance of `OverlayScreen` to be accessed globally
                    overlayScreen = OverlayScreen.of(context);
                    return child ?? const SizedBox();
                  },
                ),
              ],
            );
          },
        );
      }
    }
    
    

    To finalise lets create our HomePage and access our overlayScreen there there

    import 'package:flutter/material.dart';
    import 'package:overlay_all_app/src/overlay_screen.dart';
    
    class HomePage extends StatelessWidget {
      const HomePage({super.key});
    
      @override
      Widget build(BuildContext context) {
        // Create an instance of OverlayScreen
        final overlayScreen = OverlayScreen.of(context);
    
        return Scaffold(
          appBar: AppBar(
            title: const Text('Home'),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                TextButton(
                  onPressed: () {
                    // display the overlay
                    overlayScreen.show();
                  },
                  child: const Text('Display Overlay'),
                ),
                const SizedBox(height: 30),
                TextButton(
                  onPressed: () {
                    // Call your next screen here
                  },
                  child: const Text('Go to next page'),
                ),
                const SizedBox(height: 30),
                TextButton(
                  onPressed: () {
                    // removed all overlays on the screen
                    overlayScreen.closeAll();
                  },
                  child: const Text('Close Overlay'),
                ),
              ],
            ),
          ),
        );
      }
    }
    
    

    That’s it. You can use this class OverlayScreen to show/removeAll wherever you want.

    I created a PR with sample code, check it out https://github.com/antonio-nicolau/flutter-working-with-overlay

    Global Overlay

    Login or Signup to reply.
  3. MaterialApp(
            navigatorKey: getIt.get<NavigatorService>().navigatorKey,
            theme: AppTheme.defaultTheme,
            initialRoute: AppRoutes.splashScreen,
            builder: (context, child) {
              return Scaffold(
                body: Stack(
                  children: [
                    child!,
                    Positioned(
                      top: 15,
                      child: Container(
                        color: Colors.red,
                        height: 50,
                        width: MediaQuery.of(context).size.width,
                        child: const Center(child: Text("HI I AM AN OVERLAY")),
                      ),
                    ),
                  ],
                ),
              );
            },
            onGenerateRoute: AppRoutes.onGenerateRoute,
          ),
    

    enter image description here

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