How to check which the current Route is?

DartFlutter

Dart Problem Overview


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!

Dart Solutions


Solution 1 - Dart

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

Solution 2 - Dart

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

Solution 3 - Dart

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

Solution 4 - Dart

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

Solution 5 - Dart

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

Solution 6 - Dart

ModalRoute.of(context).settings.name

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

Solution 7 - Dart

Based on Rémi Rousselet answer.

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

Solution 8 - Dart

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

Solution 9 - Dart

Am using this code.

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

Output:

> Shows Always false current page not finding

Solution 10 - Dart

This is my solution.

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

Solution 11 - Dart

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

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

Solution 12 - Dart

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMarkoView Question on Stackoverflow
Solution 1 - DartRémi RousseletView Answer on Stackoverflow
Solution 2 - DartikbenView Answer on Stackoverflow
Solution 3 - Dartjonatas BorgesView Answer on Stackoverflow
Solution 4 - DartjglatreView Answer on Stackoverflow
Solution 5 - DartjurrdbView Answer on Stackoverflow
Solution 6 - Darthanxu317 HanView Answer on Stackoverflow
Solution 7 - DartStasVoView Answer on Stackoverflow
Solution 8 - DartGiuseppe InnocentiView Answer on Stackoverflow
Solution 9 - DartVinoth MView Answer on Stackoverflow
Solution 10 - DartfersoView Answer on Stackoverflow
Solution 11 - DartDhiraj SharmaView Answer on Stackoverflow
Solution 12 - DartevalsView Answer on Stackoverflow