How to check which the current Route is?

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 prefer that in this case a new Route is not opened. This is my code so far:

Widget build(BuildContext context){
return new Drawer(
child:
new ListView(
children: <Widget>[
new ListTile(
title: new Text("NewRoute"),
onTap: () {
Navigator.of(context).pop;
Navigator.of(context).pushNamed('/NewRoute');
}
)
)
)
}

I want to use a conditional statement to check whether we are on a certain route. I know there is a way to check which Route we are on currently with the isCurrent of the Route class

https://docs.flutter.io/flutter/widgets/Route/isCurrent.html

though I am not sure how to implement it.

Thank you in advance!

79592 次浏览

Navigator doesn't expose the current route.

What you can do instead is use Navigator.popUntil(callback) as popUtil pass to the callback the current Route, which includes it's name and stuff.

final newRouteName = "/NewRoute";
bool isNewRouteSameAsCurrent = false;


Navigator.popUntil(context, (route) {
if (route.settings.name == newRouteName) {
isNewRouteSameAsCurrent = true;
}
return true;
});


if (!isNewRouteSameAsCurrent) {
Navigator.pushNamed(context, newRouteName);
}

Use following code to check if route is top most ...

 Route route = MaterialPageRoute(builder: (context) => WidgetName());
if(route.isCurrent){
}

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(),
},
)

Am using this code.

*Route route = MaterialPageRoute(builder: (context) => Myinternet());
print(route.isCurrent);
if(route.isCurrent){
}*

Output:

Shows Always false current page not finding

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);
}

Short Way as suggested by @DarkNeuron

ModalRoute.of(context)?.settings?.name

This is my solution.

void redirect(screen){
Navigator.popUntil(context, (route) {
if ( route.settings.name != screen) {
Navigator.pushNamed(context, screen);
}
return true;
});
}
ModalRoute.of(context).settings.name

is a good API to solve this problem but this can't be used in initState();

for me i'm using the laziest easiest way since no answer here helped me in main route, i just use drawer class and pass the name of the current route to the drawer constructor like this :

class MyDrawer extends StatelessWidget {
final String currentRoute;
MyDrawer(this.currentRoute);


@override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
children: <Widget>[
InkWell(
child: Text('secondRoute'),
onTap: () {
if (currentRoute != 'secondRoute')
Navigator.push(context,
MaterialPageRoute(builder: (context) => secondRoute()));
}),
InkWell(
child: Text('thirdRoute'),
onTap: () {
if (currentRoute != 'thirdRoute')
Navigator.push(context,
MaterialPageRoute(builder: (context) => thirdRoute()));
}),

and in the routes where i call MyDrawer class i pass the name of the current route

drawer: MyDrawer('secondRoute'),

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');

This is my solution. Based on the Rémi Rousselet solution. The only difference is that prevent te pop of the "last" route remaining.

bool routeFound = false;
String routeName = "/myRoute";


//remove all the routes and stops if find the routeName or if is the last one
Navigator.popUntil(context, (route) {
if (route.settings.name == routeName) {
expenseRouteFound = true;
}
//print("route " + routeName + " founded in stack: " + routeFound.toString());
//print("last remaining route into the stack: " + route.isFirst.toString());


return routeFound || route.isFirst;
});


//print("route " + routeName + " founded in stack: " + routeFound.toString());
if (!routeFound) {
//print("time to push the route: " + routeName + "!");
Navigator.of(context).pushNamedAndRemoveUntil(routeName, (_)=>false);
}

You could just use one:

Get.currentRoute

with this package: https://pub.dev/packages/get

And you would have the current route.

However you wouldn't need this, because unlike the standard Flutter, Get prevents the user from accidentally clicking a button twice (if the user is on a low-cost device it will happen after a jank). Then you would only need to use: Get.to(Home()); and ready, it would be done!

Currently, Getx is practically indispensable for projects with Flutter for this reason. I looked at all the questions, and they are cool, but they usually involve using a popUntil to gain access to the route and this can seem like a hack when another developer reads your code. With GetX you will not have this double click problem, because it only navigates to another page of the same if you expressly disable it using Get.to(Page(), preventDuplicates: false); Remembering that this is the exception, in your case you could simply use: Get.to(Page()); and navigate to the next page without any risk of duplicate routes, because preventing that sort of thing already comes standard on it.

Getting the current route also seems to be something that involves a lot of boilerplate, with Get you get the name of the current route (even if you don't have named routes it will give you the name of it anyway), using a simple: Get.currenteRoute.

Well, it's a little late to answer that, but I hope you and other users who read this enjoy

Based on Rémi Rousselet answer.

String? currentPath;
navigatorKey.currentState?.popUntil((route) {
currentPath = route.settings.name;
return true;
});

Just use Get.currentRoute.

print(Get.currentRoute);

Output :

flutter: /ScheduleOrBookNowScreen

You can use the router:

Router.of(context).routeInformationProvider?.value.location