Navigator from MaterialApp builder

Viewed 5036

I'm trying to embed my whole App into an AppBar and a Footer. So I tried giving a custom Builder to my MaterialApp which look like this (I replaced the footer and the app bar by a button for clarity)

import 'package:epicture/scenes/Landing.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      initialRoute: '/',
      builder: (context, child) => Container(
          child: FlatButton(
                child: Text('Click me'),
                onPressed: () => Navigator.of(context).pushNamed('/app'),
      )),
      // In my current code
      builder: (context, child) => Embedder(child),
      routes: <String, WidgetBuilder>{
        '/': (context) => Landing(),
        '/app': (context) => Text('My App !'),
      },
    );
  }
}

But on press of the 'Click me' button, an error is raised saying that the context doesn't have a Navigator

the context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget

But actually, the button is a footer that can be clicked to change page from every page.

I would like to know how to have access to the navigator from the custom builder and if I simply head toward the wrong way for having the same pattern in every page of my application (Footer + header)

2 Answers

You cannot access Navigator with context from inside the builder as any widget returned by this builder will be parent for the navigator.

So, what do I do? Can I access navigator here, how?

Yeah! You can, create a GlobalKey and pass it to your MaterialApp. Then use that key to access Navigator inside your builder.

Example:

import 'package:epicture/scenes/Landing.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  final GlobalKey<NavigatorState> _navigator = GlobalKey<NavigatorState>();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      initialRoute: '/',
      navigatorKey: _navigator,
      builder: (context, child) {
        return Container(
          child: FlatButton(
            child: Text('Click me'),
            onPressed: () => _navigator.currentState.pushNamed('/app'),
          ),
        );
      },
      routes: <String, WidgetBuilder>{
        '/': (context) => Landing(),
        '/app': (context) => Text('My App !'),
      },
    );
  }
}

Hope that helps!

Rename this context variable to something else

builder: (context, child)

You are getting name clashs for the context you are using here:

onPressed: () => Navigator.of(context).pushNamed('/app'),
Related