I have this problem when I have Nested Navigator
s. So something like,
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: "/",
routes: {
'/': (context) => SomeOneView(),
'/two': (context) => SomeTwoView(),
'/three': (context) => SomeThreeView(),
},
);
}
}
class SomeOneView extends StatefulWidget {
@override
_SomeOneViewState createState() => _SomeOneViewState();
}
class _SomeOneViewState extends State<SomeOneView> {
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: double.infinity,
color: Colors.indigo,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MaterialButton(
color: Colors.white,
child: Text('Next'),
onPressed: () => Navigator.of(context).pushNamed('/two'),
),
],
),
);
}
}
class SomeTwoView extends StatefulWidget {
@override
_SomeTwoViewState createState() => _SomeTwoViewState();
}
class _SomeTwoViewState extends State<SomeTwoView> {
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
// Some implementation
},
child: Navigator(
initialRoute: "two/home",
onGenerateRoute: (RouteSettings settings) {
WidgetBuilder builder;
switch (settings.name) {
case "two/home":
builder = (BuildContext context) => HomeOfTwo();
break;
case "two/nextpage":
builder = (BuildContext context) => PageTwoOfTwo();
break;
}
return MaterialPageRoute(builder: builder, settings: settings);
},
),
);
}
}
class HomeOfTwo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: double.infinity,
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MaterialButton(
color: Colors.white,
child: Text('Next'),
onPressed: () => Navigator.of(context).pushNamed('two/nextpage'),
),
],
),
);
}
}
class PageTwoOfTwo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: double.infinity,
color: Colors.teal,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MaterialButton(
child: Text('Next'),
onPressed: () => Navigator.of(context).pushNamed('/three'),
),
],
),
);
}
}
So as you can see, I navigate from the Top Most Navigator
provided by MaterialApp
going down to the child Navigator
's 'two/nextpage'
which should then go to MaterialApp
'/three'
. The problem is that doing onPressed: () => Navigator.of(context).pushNamed('/three'),
returns the Navigator
of the current context
which is the child Navigator
. I need to access the MaterialApp
's Navigator
to navigate correctly. What is the right way to do this?
Also how to handle the case where the Navigator
I want to access is somewhere in the middle of a stack of Navigator
s?
Actually you'd have to use nested
Navigator
when you have a sub navigation flow or inner journey. Please read the docs of nesting navigators.However to get access to root navigator, you can recursively look for the parent
Navigator
from currentNavigator
and return currentNavigator
when it has no parentNavigator
.Example:
EDIT:
Solution 1 :
To get a specific parent
Navigator
, I can think of extending currentNavigator
class to accept anid
and find theNavigator
byid
. Something like:Use
NavigatorWithId
instead ofNavigator
whenever required, likeThen access it like:
Solution 2 :
Pass
ValueKey
to the navigator and make a util function that would match key and return the requiredNavigator
.A function something like
Use
and access it like
The drawback of this method I can see as not all types of keys would be supported.
Note: I don't claim any of the above solutions to be best or optimal. These are few methods I came up with. If someone can come up with better approach, I'm eager to learn :)
Hope this helps!
Most of the time, you'll have only 2 Navigator.
Which means to obtain the nested one, do:
And to obtain the root one do:
For more complex architecture, the easiest by far is to use GlobalKey (since you'll never read Navigators during build)
Which you can then use this way: