I have a drawer with named routes to different search pages. Pushing a route navigates to a search page. Each item in a search page navigates to a detail page. The back button pops the detail page and I'm back on the search page. This scenario makes the proper use of the navigator stack.
But how can I switch between multiple search pages? I can only pop one search page and then push another one.
Another use case I'm looking for is to switch between detail pages. In this case, the Navigator would hold (in this order): first search page, first detail page, second search page, second detail page. I want to switch between the two detail pages.
Is there any way to peek into the Navigator stack and bring the peeked entry to the top of the stack?
Do multiple Navigators help here? Can I switch between Navigators?
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
GlobalKey<NavigatorState> navKey = GlobalKey( );
void main( ) => runApp( MyApp( ) );
class MyApp extends StatelessWidget {
final Provider<MyMenu> menuProvider = Provider(
builder: ( context ) => MyMenu( ) );
@override
Widget build( BuildContext context ) {
return MultiProvider(
child: MaterialApp(
title: 'My App',
home: MyHomePage( ),
navigatorKey: navKey,
routes: {
routePage1: ( context ) => Page1( ),
routePage2: ( context ) => Page2( ),
},
theme: ThemeData( primarySwatch: Colors.blue, ),
),
providers: [
menuProvider,
], );
}
}
class MyMenu extends StatelessWidget {
@override
Widget build( BuildContext context ) {
String currentRoute = getCurrentRouteName( );
return Drawer( child: ListView( children: <Widget>[
ListTile(
leading: Icon( Icons.home ),
onTap: ( ) => navigateTo( context, routePage1 ),
selected: currentRoute == routePage1,
title: Text( "Page 1" ),
),
ListTile(
onTap: ( ) => navigateTo( context, routePage1 ),
selected: currentRoute == routePage1,
title: Text( "Page 1" ),
),
ListTile(
onTap: ( ) => navigateTo( context, routePage2 ),
selected: currentRoute == routePage2,
title: Text( "Page 2" ),
),
],
),
);
}
}
String getCurrentRouteName( ) {
String currentRouteName;
navKey.currentState.popUntil( ( route ) {
currentRouteName = route.settings.name;
return true;
} );
return currentRouteName;
}
void navigateTo( BuildContext context, String namedRoute, { Object arguments } ) {
// --- Close drawer menu if open
if ( Scaffold
.of( context )
.isDrawerOpen ) {
navKey.currentState.pop( );
}
// --- No navigation if target page already active
String currentRoute = getCurrentRouteName( );
if ( currentRoute == namedRoute ) return;
// --- Navigate to target
if ( currentRoute == "/" ) {
navKey.currentState.pushNamed( namedRoute, arguments: arguments );
} else {
navKey.currentState.popAndPushNamed( namedRoute, arguments: arguments );
}
}
class MyAppBar extends StatelessWidget implements PreferredSizeWidget {
@override
Widget build( BuildContext context ) {
String currentRoute = getCurrentRouteName( );
return AppBar(
leading: MenuButton( ),
title: Text( 'my app -> ${currentRoute}' ), );
}
@override
Size get preferredSize => Size.fromHeight( kToolbarHeight );
}
class MenuButton extends StatelessWidget {
@override
Widget build( BuildContext context ) {
return IconButton(
icon: Icon( Icons.menu ),
onPressed: ( ) {
ScaffoldState scaffold = Scaffold.of( context );
if ( scaffold.isDrawerOpen ) {
navKey.currentState.pop( );
} else {
scaffold.openDrawer( );
}
},
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build( BuildContext context ) {
return Scaffold(
appBar: MyAppBar( ),
body: Center(
child: Text( "This is the Homepage" ),
),
drawer: Provider.of<MyMenu>( context ),
);
}
}
const String routePage1 = '/page1';
class Page1 extends StatelessWidget {
@override
Widget build( BuildContext context ) {
return Scaffold(
appBar: MyAppBar( ),
body: Center(
child: Text( "This is Page 1" ),
),
drawer: Provider.of<MyMenu>( context ),
);
}
}
const String routePage2 = '/page2';
class Page2 extends StatelessWidget {
@override
Widget build( BuildContext context ) {
return Scaffold(
appBar: MyAppBar( ),
body: Center(
child: Text( "This is Page 2" ),
),
drawer: Provider.of<MyMenu>( context ),
);
}
}