Navigator operation requested with a context that does not include a Navigator

Flutter

Flutter Problem Overview


I'm trying to start a new screen within an onTap but I get the following error:

> Navigator operation requested with a context that does not include a > Navigator.

The code I am using to navigate is:

onTap: () { Navigator.of(context).pushNamed('/settings'); },

I have set up a route in my app as follows:

routes: <String, WidgetBuilder>{
    '/settings': (BuildContext context) => new SettingsPage(),
},

I've tried to copy the code using the stocks sample application. I've looked at the Navigator and Route documentation and can't figure out how the context can be made to include a Navigator. The context being used in the onTap is referenced from the parameter passed into the build method:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

SettingsPage is a class as follows:

class SettingsPage extends Navigator {

Widget buildAppBar(BuildContext context) {
  return new AppBar(
    title: const Text('Settings')
  );
}

@override
Widget build(BuildContext context) {
  return new Scaffold(
    appBar: buildAppBar(context),
  );
 }
}

Flutter Solutions


Solution 1 - Flutter

TLDR: Wrap the widget which needs to access to Navigator into a Builder or extract that sub-tree into a class. And use the new BuildContext to access Navigator.


This error is unrelated to the destination. It happens because you used a context that doesn't contain a Navigator instance as parent.

How do I create a Navigator instance then ?

This is usually done by inserting in your widget tree a MaterialApp or WidgetsApp. Although you can do it manually by using Navigator directly but less recommended. Then, all children of such widget can access NavigatorState using Navigator.of(context).

Wait, I already have a MaterialApp/WidgetsApp !

That's most likely the case. But this error can still happens when you use a context that is a parent of MaterialApp/WidgetsApp.

This happens because when you do Navigator.of(context), it will start from the widget associated to the context used. And then go upward in the widget tree until it either find a Navigator or there's no more widget.

In the first case, everything is fine. In the second, it throws a

> Navigator operation requested with a context that does not include a Navigator.

So, how do I fix it ?

First, let's reproduce this error :

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Center(
        child: RaisedButton(
          child: Text("Foo"),
          onPressed: () => Navigator.pushNamed(context, "/"),
        ),
      ),
    );
  }
}

This example creates a button that attempts to go to '/' on click but will instead throw an exception.

Notice here that in the

  onPressed: () => Navigator.pushNamed(context, "/"),

we used context passed by to build of MyApp.

The problem is, MyApp is actually a parent of MaterialApp. As it's the widget who instantiate MaterialApp! Therefore MyApp's BuildContext doesn't have a MaterialApp as parent!

To solve this problem, we need to use a different context.

In this situation, the easiest solution is to introduce a new widget as child of MaterialApp. And then use that widget's context to do the Navigator call.

There are a few ways to achieve this. You can extract home into a custom class :

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHome()
    );
  }
}

class MyHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
        child: RaisedButton(
          child: Text("Foo"),
          onPressed: () => Navigator.pushNamed(context, "/"),
        ),
      );
  }
}

Or you can use Builder :

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Builder(
        builder: (context) => Center(
              child: RaisedButton(
                child: Text("Foo"),
                onPressed: () => Navigator.pushNamed(context, "/"),
              ),
            ),
      ),
    );
  }
}

Solution 2 - Flutter

Hy guys, i have the same problem. This is occur for me. The solution what i found is very simple. Only what i did is in a simple code:

void main() {
  runApp(MaterialApp(
    home: YOURAPP() ,
    ),
  );
}

I hope was useful.

Solution 3 - Flutter

Make sure your current parent widget not with same level with MaterialApp

Wrong Way

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          centerTitle: true,
          title: Text('Title'),
        ),
        body: Center(
            child: Padding(
          padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
          child: RaisedButton(
              onPressed: () {
                //wrong way: use context in same level tree with MaterialApp
                Navigator.push(context,
                    MaterialPageRoute(builder: (context) => ScanScreen()));
              },
              child: const Text('SCAN')),
        )),
      ),
    );
  }
}

Right way

void main() => runApp(MaterialApp(
      title: "App",
      home: HomeScreen(),
    ));

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: Text('Title'),
      ),
      body: Center(
          child: Padding(
        padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
        child: RaisedButton(
            onPressed: () {
            //right way: use context in below level tree with MaterialApp
              Navigator.push(context,
                  MaterialPageRoute(builder: (context) => ScanScreen()));
            },
            child: const Text('SCAN')),
      )),
    );
  }
}

Solution 4 - Flutter

I set up this simple example for routing in a flutter app:

import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      home: new MyHomePage(),
      routes: <String, WidgetBuilder>{
        '/settings': (BuildContext context) => new SettingsPage(),
      },
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('TestProject'),
      ),
      body: new Center(
        child: new FlatButton(
          child: const Text('Go to Settings'),
          onPressed: () => Navigator.of(context).pushNamed('/settings')
        )
      )
    );
  }
}

class SettingsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text('SettingsPage'),
        ),
        body: new Center(
            child: new Text('Settings')
        )
    );
  }
}

Note, that the SettingsPage extends StatelessWidget and not Navigator. I'm not able to reproduce your error.

Does this example help you in building your app? Let me know if I can help you with anything else.

Solution 5 - Flutter

Just like with a Scaffold you can use a GlobalKey. It doesn't need context.

final _navKey = GlobalKey<NavigatorState>();

void _navigateToLogin() {
  _navKey.currentState.popUntil((r) => r.isFirst);
  _navKey.currentState.pushReplacementNamed(LoginRoute.name);
}

@override
Widget build(BuildContext context) {
  return MaterialApp(
    navigatorKey: _navKey,
    ...
  );
}

Solution 6 - Flutter

You should rewrite your code in main.dart FROM:

void main() => runApp(MyApp());

TO

void main() {
  runApp(MaterialApp(
  title: 'Your title',
  home: MyApp(),));}

The point is to have the home property to be your first page this worked for me, I hope it will help someone in the future

Solution 7 - Flutter

A complete and tested solution:

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:my-app/view/main-view.dart';

class SplashView extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        home: Builder(
          builder: (context) => new _SplashContent(),
        ),
        routes: <String, WidgetBuilder>{
          '/main': (BuildContext context) => new MainView()}
    );
  }
}

class _SplashContent extends StatefulWidget{

  @override
  _SplashContentState createState() => new _SplashContentState();
}

class _SplashContentState extends State<_SplashContent>
    with SingleTickerProviderStateMixin {

  var _iconAnimationController;
  var _iconAnimation;

  startTimeout() async {
    var duration = const Duration(seconds: 3);
    return new Timer(duration, handleTimeout);
  }

  void handleTimeout() {
    Navigator.pushReplacementNamed(context, "/main");
  }

  @override
  void initState() {
    super.initState();

    _iconAnimationController = new AnimationController(
        vsync: this, duration: new Duration(milliseconds: 2000));

    _iconAnimation = new CurvedAnimation(
        parent: _iconAnimationController, curve: Curves.easeIn);
    _iconAnimation.addListener(() => this.setState(() {}));

    _iconAnimationController.forward();

    startTimeout();
  }

  @override
  Widget build(BuildContext context) {
    return new Center(
        child: new Image(
          image: new AssetImage("images/logo.png"),
          width: _iconAnimation.value * 100,
          height: _iconAnimation.value * 100,
        )
    );
  }
}

Solution 8 - Flutter

As per this comment If your navigator is inside Material context navigator push will give this error. if you create a new widget and assign it to the material app home navigator will work.

This won't work

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text("Title"),
        ),
        body: new Center(child: new Text("Click Me")),
        floatingActionButton: new FloatingActionButton(
          child: new Icon(Icons.add),
          backgroundColor: Colors.orange,
          onPressed: () {
            print("Clicked");
            Navigator.push(
              context,
              new MaterialPageRoute(builder: (context) => new AddTaskScreen()),
            );
          },
        ),
      ),
    );
  }
}

This will work

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        home: new HomeScreen());
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Title"),
      ),
      body: new Center(child: new Text("Click Me")),
      floatingActionButton: new FloatingActionButton(
        child: new Icon(Icons.add),
        backgroundColor: Colors.orange,
        onPressed: () {
          print("Clicked");
          Navigator.push(
            context,
            new MaterialPageRoute(builder: (context) => new AddTaskScreen()),
          );
        },
      ),
    );
  }
}

Solution 9 - Flutter

I was facing the same problem and solved by removing home from MaterialApp and use initialRoute instead.

return MaterialApp(
      debugShowCheckedModeBanner: false,
      initialRoute: '/',
      routes: {
        '/': (context) => MyApp(),
        '/settings': (context) => SettingsPage(),
      },
    );

And

onTap: () => {
               Navigator.pushNamed(context, "/settings")
                },

Solution 10 - Flutter

It happens because the context on the widget that tries to navigate is still using the material widget.

The short answer for the solution is to :

> extract your widget

that has navigation to new class so it has a different context when calling the navigation

Solution 11 - Flutter

When your screen is not navigated from other screen,you don't initially have access to the navigator,Because it is not instantiated yet.So in that case wrap your widget with builder and extract context from there.This worked for me.

builder: (context) => Center(
              child: RaisedButton(
                child: Text("Foo"),
                onPressed: () => Navigator.pushNamed(context, "/"),
              ),

Solution 12 - Flutter

You ca use this plugin https://pub.dev/packages/get/versions/2.0.2

in The MaterialApp assign property navigatorKey: Get.key,

MaterialApp(
      navigatorKey: Get.key,
      initialRoute: "/",
     );

you can access Get.toNamed("Your route name");

Solution 13 - Flutter

Change your main function example:

void main() {
    runApp(
        MaterialApp(
            title: 'Your title',
            home: MyApp(),
        )
    );
}

Solution 14 - Flutter

use this

void main() {
  runApp(MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()),);
}

instead of this

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

Wrap with materialapp

reproduce code

import 'dart:convert';

import 'package:flutter/material.dart';

void main() {
  // reproduce code
  runApp(MyApp());
  // working switch //
  // runApp(
  //
  //   MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()),);
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Scaffold(
            body:
                Column(mainAxisAlignment: MainAxisAlignment.center, children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Container(
                height: 100,
                width: 100,
                child: ElevatedButton(
                  onPressed: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => IntroPage(Isscar4: true)),
                    );
                  },
                  child: RichText(
                      text: TextSpan(
                    text: 'CAR',
                    style: TextStyle(
                        letterSpacing: 3,
                        color: Colors.white,
                        fontWeight: FontWeight.w400),
                    children: [
                      TextSpan(
                          text: '4',
                          style: TextStyle(
                              fontSize: 25,
                              color: Colors.red,
                              fontWeight: FontWeight.bold))
                    ],
                  )),
                ),
              ),
            ],
          ),
          SizedBox(
            height: 10,
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Container(
                height: 100,
                width: 100,
                child: ElevatedButton(
                  onPressed: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => IntroPage(Isscar4: false)),
                    );
                  },
                  child: RichText(
                      text: TextSpan(
                    text: 'BIKE',
                    style: TextStyle(
                        letterSpacing: 3,
                        color: Colors.white,
                        fontWeight: FontWeight.w400),
                    children: [
                      TextSpan(
                          text: '2',
                          style: TextStyle(
                              fontSize: 25,
                              color: Colors.red,
                              fontWeight: FontWeight.bold))
                    ],
                  )),
                ),
              ),
            ],
          )
        ])));
  }

  MaterialApp Swithwidget(istrue) {
    return MaterialApp(
      home: Scaffold(
        body: IntroPage(
          Isscar4: istrue,
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text("df"),
    );
  }
}

class IntroPage extends StatelessWidget {
  final Isscar4;

  IntroPage({
    Key? key,
    required this.Isscar4,
  }) : super(key: key);

  List<Widget> listPagesViewModel = [];

  List<IntroModel> models = [];

  @override
  Widget build(BuildContext context) {
    List<dynamic> intro = fetchIntroApi(Isscar4);

    intro.forEach((element) {
      var element2 = element as Map<String, dynamic>;
      var cd = IntroModel.fromJson(element2);
      models.add(cd);
    });
    models.forEach((element) {
      listPagesViewModel.add(Text(""));
    });

    return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Scaffold(
          body: Container(),
        ));
  }

  List fetchIntroApi(bool bool) {
    var four = bool;
    if (four) {
      var data =
          '[ {"name_Title": "title name1","description": "description1"}, {"name_Title": "title name2","description": "description2"}, {"name_Title": "title name3","description": "description3"}, {"name_Title": "title name4","description": "description4"} ]';
      return json.decode(data);
    } else {
      var data =
          '[ {"name_Title": "title name","description": "description1"}, {"name_Title": "title name2","description": "description2"}, {"name_Title": "title name3","description": "description3"} ]';

      return json.decode(data);
    }
  }
}

class IntroModel {
  String? nameTitle;
  String? description;

  IntroModel({this.nameTitle, this.description});

  IntroModel.fromJson(Map<String, dynamic> json) {
    nameTitle = json['name_Title'];
    description = json['description'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['name_Title'] = this.nameTitle;
    data['description'] = this.description;
    return data;
  }
}

Solution 15 - Flutter

Builder( builder: (context) { return TextButton( child: const Text('Bearbeiten'), onPressed:(){ Navigator.push( context, MaterialPageRoute(builder: (context) => const gotothesiteyouwant()), );
}); } ),

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjuliusspencerView Question on Stackoverflow
Solution 1 - FlutterRémi RousseletView Answer on Stackoverflow
Solution 2 - FlutterGustavo BernedView Answer on Stackoverflow
Solution 3 - FlutterMahmoud Abu AlhejaView Answer on Stackoverflow
Solution 4 - FlutterRainer WittmannView Answer on Stackoverflow
Solution 5 - FlutterVadim OsovskyView Answer on Stackoverflow
Solution 6 - FlutterMohammed H. HannoushView Answer on Stackoverflow
Solution 7 - FlutterGiBiView Answer on Stackoverflow
Solution 8 - FlutterlakshmanView Answer on Stackoverflow
Solution 9 - FlutterShifaTView Answer on Stackoverflow
Solution 10 - FluttersurgaView Answer on Stackoverflow
Solution 11 - FlutterVamsi KrishnaView Answer on Stackoverflow
Solution 12 - FlutterYoussef ElsayghView Answer on Stackoverflow
Solution 13 - FlutterRohit SharmaView Answer on Stackoverflow
Solution 14 - FlutterlavaView Answer on Stackoverflow
Solution 15 - FlutterSebastian de la VegaView Answer on Stackoverflow