Navigating Flutter Part 2

Greg Perry
Jan 16 · 9 min read

A look into Flutter’s Navigation System

In part 2 of this series, we’ll continue our look at Flutter’s navigation system and examine another approach used to navigate from screen to screen in your Flutter app. This approach works with ‘named routes’, using the static function, Navigator.pushNamed(). We’ll also look at what’s involved when you go back through the ‘route stack’ with the static function,Navigator.pop().

Flutter Navigation Part 1

I Like Screenshots. Click For Gists.

As always, I prefer using screenshots in my articles over gists to show concepts rather than just show code. I find them easier to work with frankly. However, you can click or tap on these screenshots to see the code in a gist or in Github. Further, it’s better to read this article about mobile development on your computer than on your phone. Besides, we program mostly on our computers — not on our phones. Not yet anyway.

Let’s begin.

Other Articles by Greg Perry

The MaterialApp widget has a named parameter called, routes. It takes in a Map object of type,<String, WidgetBuilder>{}, with a function-type alias, WidgetBuilder.This alias defines the following function signature to create a widget, Widget Function(BuildContext context);. Below is a screenshot of the example app we’re using in this article called, navigate_with_named_routes.dart. You can see the ‘route table’ contains two entries, and their map keys are strings — the name of the route, and each map value is a function that returns a widget. Pretty straight forward.


What’s In A Name?

The parameter, routes, is referred to as the ‘routes table’, and it works with the ‘named routes’ approach (Navigator.pushNamed()) to have you move from screen to screen. It’s suggested such a table is implemented when apps have either a large number of routes (screens) or when the app has many separate screens repeatedly navigating to the same screen — all to reduce code duplication. It’s suggested, in such situations, a ‘routes table’ would also be easier to maintain.

An example of the ‘named route’ approach is displayed in the screenshot below. The static function, Navigator.pushNamed(), is called passing in two positional parameters: BuildContext context and String routeName.


Note the pushNamed() function’s signature below. In the example above, the command neglects to specify the return value’s data type. It’s not mandatory, but I would say is a better practice is to include the return value’s data type between brackets: Navigator.pushNamed<dynamic>(context, '/second/);

static Future<T> pushNamed<T extends Object>(
BuildContext context,
String routeName, {
Object arguments,

The function returns a Future object of that specified data type. Dealing with a Future returned value implies you’re free ‘to wait’ at that command line for a returned value using the operator, await. The example above does just that.

Note, there’s a third named-parameter in the pushNamed() function many are not aware of called, arguments. We’ll look into that shortly. Right now, let’s walk through the code and see what happens when the pushNamed() function is called. This will involve a running commentary on a series of screenshots below, and we’ll start with the pushNamed() function itself.

And so inside the function, we see the commonly used static function, Navigatoar.of(). It retrieves the State object, NavigatorState, to then call, in turn, its own pushNamed() function passing on the ‘route name’ and any arguments. See below.


Now, in its pushNamed() function, we see the conventional push() function is then used, but not before the private function, _routeNamed, takes in the the ‘route name’ and any arguments and returns a Route object.


Looking into the private function, _routeNamed, you’ll find the onGenerateRoute() function defined in the StatefulWidget, Navigator, will then take you to the widget, WidgetsApp, and its own private function, _onGenerateRoute(). Still with me?


It’s in that private function (see below), where the ‘routes table’ is first accessed looking up the specified route name with, widget.routes[name];. Looking carefully, you can see the assigned variable, pageContentBuilder, is tested for null. If the provided name is indeed found in the Map object, routes, a Route object is returned using the corresponding WidgetBuilder found in the Map object.


Note, you may remember from Part 1, the routine, widget.pageRouteBuilder<dynamic>(), is the anonymous function supplied to the WidgetsApp as you see in the screenshot below. It takes in from the function, _onGenerateRoute(), the ‘RouteSettings’ and ‘WidgetBuilder’ objects and returns the appropriate ‘Route’ object depending on the ‘Interface design:’ Material or Cupertino.


A Route With No Name

Returning to the _WidgetsAppState object and its function, _onGenerateRoute, listed again below, if the route name is not found in the Map object, routes, and the variable, pageContentBuilder, is then null, an alternative operation may occur. Note the red arrow below highlights the MaterialApp’s onGenerateRoute parameter.


In the screenshot below, that parameter, onGenerateRoute, is not null in this particular example app. It’s supplied a static function from the class, Router. And with that, note the ‘route table’ has merely two entries one of which is assigned as the ‘home screen’ (initialRoute: '/') and so is already called and displayed when the app first starts up. So, what happens when the button, ‘Third screen’, is pressed in the example app?

What happens is the variable, pageContentBuilder, is null, but the instance field, onGenerateRoute, is not. Thus, the defined routine in the class, Router, (below on the right) is called passing in the object, settings, of type RouteSettings. And so when the button, Third screen, is pressed, the static function, Navigator.pushNamed(), is called (below on the left) with the route name, ‘/third.’ As you see on the right, however, the ‘Router’ routine has an entry in its switch-case that matches that name. With that, the appropriate MaterialPageRoute object is returned all the way back to the NavigatorState’s private function, _routeNamed(). Clear as mud.

With all that, a Route object is now supplied to the push() function while continuing to specify the returned value data type, T. Note, it’s required that generic type be extended by Object.


We’ll now look into the push() function and see what’s involved. Note, below you see the Route object is added to the List instance field, _history. As you may know, it is this variable that represents the ‘stack of routes’ that comes about when going from screen to screen. The function ends with the getter, popped. Of course, since this function returns a Future which is to contain the result value of a particular data type, T, this is where we essentially wait for the user to return from the screen just selected.


Pop Completes A Future

As it states in the documentation below, the getter, popped, waits here until the ‘pushed’ route is completed and is ‘popped off.’ Keep in mind, the generic type, T, is passed on so to identify the data type that is to be returned as a result if any.


What’s Your Argument?

Let’s take a quick look back at the pushNamed() function with that third named-parameter you may not be aware of called, arguments. As you know now, that parameter is of type, Object, allowing you to pass *any* object you like and pass it along to later be cast to the specific class type you’re expecting. Let’s walk through the code now to see what happens when you pass ‘an argument’ in the pushNamed() function. In the example app, a pretty self-explanatory String object is passed as an argument.


And so, when one of those pushNamed() functions is called and we’re to navigate to the third screen, for example, the RouteSettings object contains any and all arguments that are to be passed along. This is true for the fourth screen as well. Got it?


Note, the RouteSettings object provides the arguments field instance, granted, but it is up to the developer to then determine how to deliver that object to the subsequent screen if need be. The most obvious approach I would say is to include the object as an explicit parameter to the StatelessWidgt in this case. And that’s about it when it comes to that unknown ‘arguments’ parameter.


When It Pops

Finally, let’s walk through the code involved when the ‘route stack’ does retreat back to the previous screen with the command, Navigator.pop();. Looking in the pop() function, we see the Navigator's State object, NavigatorState, is retrieved and its own pop() function is called in turn — passing in the optional result value of data type, T.


A Route To History

It’s in the State object, NavigatorState, where we again see the ‘route stack’ in the form of a List object called, _history. The last entry in that List object is retrieved containing the route that’s just been ‘popped.’ This ‘route entry’ object has its own pop() function and it too is called passing in the result value if any. As you see in the screenshots below, there are three more functions called until finally the Completer object waiting in the push() function is indeed completed with the specified result value.


In the example app, when clicking back from the Third screen, we see in the screenshot below that the result value returned is the string, ‘Third Screen argument.’

We’ll continue our examination of the Navigation system offered by Flutter with subsequent articles. There are still other options available to you when moving around your app. Flutter has a lot to offer. You just have to walk through the code to find it.


Flutter Navigation Part 3

→ Other Stories by Greg Perry

DECODE Flutter on YouTube

Flutter Community

Articles and Stories from the Flutter Community

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app