skip to Main Content

I am trying to get a navigator to work on my icons. I have all my icons laid out in a column, which persists across all my screens and I want to be able to go to different screens when I click an icon on the left within my menu. The icons in the bottom right corner have been disabled, I am just using those to refer to the first and second page.

enter image description here

I have set up a navigator within the MyApp widget, which has routes to a couple test pages called firstpage and secondpage, although when I click the icons and try to route over to the another page I get this error:

The following assertion was thrown while handling a gesture:
Navigator operation requested with a context that does not include a Navigator.

I’m assuming that I am not using the navigator correctly but I’m not sure what I need to do.

main.dart

import 'package:flutter/material.dart';
import 'package:practice3/secondpage.dart';
import 'firstpage.dart';
import 'package:flutter/services.dart';
import 'persistentmenu.dart';
import 'persistentrow.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();

  SystemChrome.setPreferredOrientations(
    [DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight],
  ).then((_) {
    runApp(const MyApp());
  });
}

class BaseWidget extends StatelessWidget {

  final Widget child;

  const BaseWidget({required this.child});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Stack(
          children: [
            Container(child: child),
            PersistentRow(),
            PersistentMenu(),
          ],
        )
    );
  }
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      builder: (context, child) => BaseWidget(child: child!),
      initialRoute: '/',
      routes: {
        '/': (context) => FirstPage(),
        '/second': (context) => SecondPage(),
      },
    );
  }
}

persistentmenu.dart


import 'package:flutter/material.dart';
import 'firstpage.dart';
import 'secondpage.dart';

class PersistentMenu extends StatelessWidget {

 @override
 Widget build(BuildContext context) {
   return SafeArea(
     child: Align(
       alignment: Alignment.bottomLeft,
       child: Container(
         width:  80,
         height: 800,
         //margin: EdgeInsets.only(right: 25),
         color: Color.fromRGBO(2, 58, 107, 1),
         child: Column(
           mainAxisAlignment: MainAxisAlignment.spaceEvenly,
           children: <Widget>[
             IconButton(
               padding: EdgeInsets.all(0.0),
               icon: Image.asset('assets/icons/Back.png'),
               onPressed: () {
                Navigator.pushNamed(context, '/'); // Route to firstpage.dart
               },
             ),
             IconButton(
               padding: EdgeInsets.all(0.0),
               icon: Image.asset('assets/icons/tip_load.png'),
               onPressed: () {},
             ),
             IconButton(
               padding: EdgeInsets.all(0.0),
               icon: Image.asset('assets/icons/tip_eject.png'),
               onPressed: () {},
             ),
             IconButton(
               padding: EdgeInsets.all(0.0),
               icon: Image.asset('assets/icons/Light.png'),
               onPressed: () {},
             ),
             IconButton(
               padding: EdgeInsets.all(0.0),
               icon: Image.asset('assets/icons/Utility.png'),
               onPressed: () {
                 Navigator.pushNamed(context, '/second'); // Route to secondpage.dart
               },
             ),
             IconButton(
               padding: EdgeInsets.all(0.0),
               icon: Image.asset('assets/icons/Help.png'),
               onPressed: () {},
             ),
             IconButton(
               padding: EdgeInsets.all(0.0),
               icon: Image.asset('assets/icons/User.png'),
               onPressed: () {},
             ),
             IconButton(
               padding: EdgeInsets.all(0.0),
               icon: Image.asset('assets/icons/Power.png'),
               onPressed: () {},
             ),
           ],
         ),
       ),
     ),
   );
 }
}

secondpage.dart

import 'package:flutter/material.dart';

class SecondPage extends StatelessWidget {

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     body: Align(
       alignment: Alignment.bottomRight,
       child: Column(
         mainAxisAlignment: MainAxisAlignment.end,
         children: <Widget>[
           ElevatedButton.icon(
             onPressed: () {
               //Navigator.pushNamed(context, '/');
             },
             icon: Icon(Icons.arrow_back_outlined),
             label: Text('Back to first Page'),
           ),
         ],
       ),
     ),
   );
 }
}

3

Answers


  1. In second Navigator. pushNamed you need to use ‘/second’ because that is the route that you have named in your main. dart file

    Login or Signup to reply.
  2. The builder property is built below the Navigator, so Navigator.of(context) will not be able to find anything. In order to use the Navigator, you need another way to access the state.

    • If you don’t need BaseWidget below the Navigator, you can simply add it as the base for both pages instead.

    • If you need BaseWidget below the Navigator (so the persistent elements will stay still during transitions), you will need to create a GlobalKey<NavigatorState> and pass it to both the MaterialApp and BaseWidget. You can then access the NavigatorState via key.currentState!.

    Login or Signup to reply.
  3. I’ve replicated this error and have fixed it. Read below for detailed solution.

    Explanation: –
    Actually, when you were passing the ‘context’ in persistentmenu.dart

     onPressed: () {
                  Navigator.pushNamed(
                      context,
                      '/'); // Route to firstpage.dart
                },
    

    You were using the context of ‘persistentmenu.dart’ file which was linked to the ‘context’ of ‘BaseWidget’ buildContext and in short that context was passed by the ‘MyApp’ class(right below the BaseWidget class) as argument due to which Navigator was unable to find the context of MaterialApp and error was being popped.
    Now there can be multiple ways to solve it as you need to somehow pass MaterialApp Context to it so that when you use the PushNamed which is actually translated to

    @optionalTypeArgs
    static Future<T?> pushNamed<T extends Object?>(
      BuildContext context,
      String routeName, {
      Object? arguments,
    }) {
      return Navigator.of(context).pushNamed<T>(routeName, arguments: arguments);
    }
    

    So you could pass the MaterialApp context or atleast the context from where the dart analyzer can go upward and search for the context of MaterialApp(Because navigator is defined in MaterialApp).
    There can be multiple ways to solve this but I solved it as follow.

    Solution
    Simply create a new class to store GlobalKey Context of MaterialApp

    NavigatorService.dart

    import 'package:flutter/material.dart';
    
        class NavigationService {
          static GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
        }
    

    Refactor ‘MyApp’ class as follow, just pass the MaterialApp context to the GlobalKey.
    main.dart

    class MyApp extends StatelessWidget {
    const MyApp({Key? key}) : super(key: key);

      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          navigatorKey: NavigationService.navigatorKey,
          debugShowCheckedModeBanner: false,
          builder: (context, child) => BaseWidget(child: child!),
          initialRoute: '/',
          routes: {
            '/': (context) => FirstPage(),
            '/second': (context) => SecondPage(),
          },
        );
      }
    }
    

    and replace the above context with ‘context’ used in Navigator.pushNamed
    firstpage.dart

    IconButton(
                        padding: EdgeInsets.all(0.0),
                        icon: const Icon(Icons.label_important_rounded),
                        onPressed: () {
                          Navigator.pushNamed(
                              NavigationService.navigatorKey.currentContext!,
                              '/'); // Route to firstpage.dart
                       },
               ),
    

    Do the same for second page as well. // Route to secondpage.dart
    I hope this will solve the issue.

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