I want to navigate to different Routes using a Drawer, though I do not want to open a new instance of a Route each time I tap on it if I am already on that Route, rather I would
This is a perfect use case for Dart extension methods (based on Rémi Rousselet's answer):
extension NavigatorStateExtension on NavigatorState {
void pushNamedIfNotCurrent( String routeName, {Object arguments} ) {
if (!isCurrent(routeName)) {
pushNamed( routeName, arguments: arguments );
}
}
bool isCurrent( String routeName ) {
bool isCurrent = false;
popUntil( (route) {
if (route.settings.name == routeName) {
isCurrent = true;
}
return true;
} );
return isCurrent;
}
}
Then it looks as clean as this:
Navigator.of(context).pushNamedIfNotCurrent('/NewRoute');
Rémi's answer really helped me, but if you're new to Flutter/Dart like me, it takes a while to understand. So here's a my version with some extra checks and explanatory documentations:
/// Navigates through the application. Only replaces the top Route if it is
/// different from the new Route. Always keeps the home page as base of the
/// Navigator stack. New screens are pushed on the Navigator stack. When the
/// user switches between non-home screens, the new screen replaces the old
/// screen. In this way, the stack of screens from the drawer is never higher
/// than 2. Returning to the HomeScreen is done by just popping the current
/// Route.
void _changeRoute(BuildContext context, String newRouteName) {
// Close drawer
Navigator.pop(context);
// Check current screen status
bool currentRouteIsHome = false;
bool currentRouteIsNewRoute = false;
Navigator.popUntil(context, (currentRoute) {
// This is just a way to access currentRoute; the top route in the
// Navigator stack.
if (currentRoute.settings.name == HomeScreen.ROUTE_NAME) {
currentRouteIsHome = true;
}
if (currentRoute.settings.name == newRouteName) {
currentRouteIsNewRoute = true;
}
// Return true so popUntil() pops nothing.
return true;
});
// Switch screen
if (!currentRouteIsNewRoute) {
// Only switch screen if new route is different from current route.
if (currentRouteIsHome) {
// Navigate from home to non-home screen.
Navigator.pushNamed(context, newRouteName);
} else {
if (newRouteName == HomeScreen.ROUTE_NAME) {
// Navigate from non-home screen to home.
Navigator.pop(context);
} else {
// Navigate from non-home screen to non-home screen.
Navigator.popAndPushNamed(context, newRouteName);
}
}
}
}
Note that this implementation with pushNamed
and popAndPushNamed
requires you to define Route
names in your top level MaterialApp
in the routes:
argument, like so:
new MaterialApp(
routes: <String, WidgetBuilder>{
// define the routes
YOUR_SCREEN_ROUTE_NAME: (BuildContext context) => new YourScreen(),
},
)
ModalRoute.of(context).settings.name
is a good API to solve this problem but this can't be used in initState();
This should give you the exact route name
import 'package:path/path.dart';
ModalRoute.of(context).settings.name
To avoid null exception do this
var route = ModalRoute.of(context);
if(route!=null){
print(route.settings.name);
}
Am using this code.
*Route route = MaterialPageRoute(builder: (context) => Myinternet());
print(route.isCurrent);
if(route.isCurrent){
}*
Output:
Shows Always false current page not finding