Building UI in Flutter is pretty simple with all the widgets that the framework provides. But we can’t just have a beautiful application that does nothing functional. We will be required to move around the application or send data back and forth between screens. In Flutter, navigation from one screen to another is possible because of Navigators, a simple widget that maintains a stack of Routes, or in simpler terms, a history of visited screens/pages.

You will find plenty of articles that tell you how to push to a new screen or pop from the current screen, but this article is a little more than that. This would primarily focus on most of the Navigator methods and describe a use-case for each method.

Before we begin…

You mentioned about Routes somewhere, what was that?
Routes is an abstraction for a screen or a page of an app. For example, '/home' will take you to HomeScreen or '/login' will take you to LoginScreen. '/' will be your initial route. This might sound so much similar to Routing in REST API development. So '/' might act like a root.

This is how you would declare your routes in your Flutter application.

new MaterialApp(
  home: new Screen1(),
  routes: <String, WidgetBuilder> {
    '/screen1': (BuildContext context) => new Screen1(),
    '/screen2' : (BuildContext context) => new Screen2(),
    '/screen3' : (BuildContext context) => new Screen3(),
    '/screen4' : (BuildContext context) => new Screen4()
  },
)

Push, push, push.

If you have any knowledge in Data Structures, then you know about Stacks. If you have even basic knowledge of stacks, then you know about push and pop.

If you don’t, pushing is adding element to the top of a stack of elements and popping is removing the top element from the same stack.

So in the case of Flutter, when we navigate to another screen, we use the push methods and Navigator widget adds the new screen onto the top of the stack. Naturally, the pop methods would remove that screen from the stack.

So let’s move to the codebase of our sample project and let’s see how we can move from Screen 1 to Screen 2. You can experiment with the methods by running the sample app.

new RaisedButton(
   onPressed:(){
   Navigator.of(context).pushNamed('/screen2');
},
   child: new Text("Push to Screen 2"),
),

That was short.

That was indeed. With the help of pushNamed methods, we can navigate to any screen whose route is defined in main.dart. We call them namedRoute for reference. The use-case of this method is pretty straightforward. To simply navigate.

Pop it

Now when we want to get rid of the last visited screen, which is Screen2 in this case, we would need to pop Routes from the Navigator’s stack using the pop methods.

Navigator.of(context).pop();

Remember, this line of code goes inside your onPressed method.

When using Scaffold, it usually isn’t necessary to explicitly pop the route, because the Scaffold automatically adds a ‘back’ button to its AppBar, which would call Navigator.pop() on pressed. Even in Android, pressing the device back button would do the same. But nevertheless, you might need this method for other usecases such as popping an AlertDialog when user clicks on Cancel button.

Why pop instead of pushing back to the previous screen?
Imagine you have a Hotel Booking app that lists the hotels in your desired location. Clicking on any list item will take you to a screen that has more details about the hotel. You choose one, and you hate the hotel and want to go back to the list. If you push back to the HotelListScreen, you will be keeping your DetailsScreen onto your stack too. So pressing on the back button would take you back to the DetailsScreenSo confusing!

You should try it out instead. Run the sample app, notice the appBar on your Screen1 , it doesn’t have any back button, because it is the initial Route (or home screen), now press Push to Screen 2 and instead of back button, press the Push to Screen1 instead of Pop and now notice the appBar on Screen1. Pressing on the newly appeared back button will take you back to Screen2 and you don’t want that in such cases.

maybePop

Now what if you are on the initial Route and somebody mistakenly tried to pop this screen. Popping the only screen on the stack would close your app, because then it has no route to display. You definitely don’t want your user to have such an unexpected user experience. That’s where maybePop() comes into the picture. So it’s like, pop only if you can. Try it out, click on the maybePop Button on Screen1 and it will do nothing. Because there is nothing to pop. Now try the same on Screen3 and it will pop the screen. Because it can.

canPop

It’s amazing that we can do this, but how can I know if this is the initial route? It would be nice if I could display some alert to user in such cases.
Great question, just call this canPop() method and it would return true if this route can be popped and false if it’s not possible.

Try both these methods canPop and maybePop on Screen1 and Screen3 and see the difference. The print values for canPop will display in your console tab of your IDE.


Push a little harder

Let’s come back to more push methods. Now we are getting deeper. We will now talk about replacing a route with a new route. We have two methods that can do this — pushReplacementNamed and popAndPushNamed.

Navigator.of(context).pushReplacementNamed('/screen4');
                       //and
Navigator.popAndPushNamed(context, '/screen4');

Try to experiment with both in the sample app’s Screen3. And notice the exit and enter animation in each case. pushReplacementNamed will execute the enter animation and popAndPushNamed will execute the exit animation. We can use this for the following possible use-cases.

Use-case : pushReplacementNamed

When the user has logged in successfully, and are now on the DashboardScreen perhaps, then you don’t want the user to go back to LoginScreen in any case. So login route should be completely replaced by the dashboard route. Another example would be going to HomeScreen from SplashScreen. It should only display once and the user should not be able to go back to it from HomeScreen again. In such cases, since we are going to a completely new screen, we may want to use this method for its enter animation property.

Use-case: popAndPushNamed

Suppose, you are building a Shopping app that displays a list of the products in its ProductsListScreen and user can apply filters in the FiltersScreen. When the user clicks on the Apply Changes button, the FiltersScreen should pop and push back to the ProductsListScreen with the new filter values. Here the exit animation property of popAndPushNamed would look more appropriate.


Until the end…

We are almost at the end of the article. Well, almost.
In this section, we will cover the following three methods pushNamedAndRemoveUntil and popUntil.

Use-case: pushNamedAndRemoveUntil

So basically you building a Facebook/Instagram like application, where user logs in, scrolls through their feed, stalks through different profiles, and when done, wants to log out of the app. After logging out, you can’t just simply push a HomeScreen (or any screen that needs to be displayed after logging out) in such cases. You want to remove all routes in the stack so that user cannot go back to the previous routes after they have logged out.

Navigator.of(context).pushNamedAndRemoveUntil('/screen4', (Route<dynamic> route) => false);

Here (Route<dynamic> route) => false will make sure that all routes before the pushed route be removed.

Now instead of removing all routes before the pushed routes, we can only remove a certain number of routes. Let’s take another Shopping app example! Or basically, any app that requires payment transactions.

So in these apps, once a user has completed the payment transaction, all the transaction or cart related screens should be removed from the stack, and the user should be taken to the PaymentConfirmationScreen. Clicking on the back button should take them back to the ProductsListScreen or HomeScreen only.

Navigator.of(context).pushNamedAndRemoveUntil('/screen4', ModalRoute.withName('/screen1'));

So according to the code snippet, we push Screen4 and remove all routes until Screen1, so our stack would look like this.

Use-case: popUntil

Imagine you are building a Google Forms like an application or an app that lets you fill and organize Google forms. Now some users might have to fill a long 3-part form, which might be displayed in 3 sequential screens in a mobile application. Now on the 3rd part of the form, the user decides to cancel filling the form. User clicks on Cancel and all the previous form related screens should be popped and the user should be taken back to the HomeScreen or DashboardScreen thereby losing all the form related data (which is what we want in such cases). We won’t be pushing anything new here, just going back to a previous route.

Navigator.popUntil(context, ModalRoute.withName('/screen2'));

By kwame

Leave a Reply

Your email address will not be published. Required fields are marked *

//