Flutter Navigation: Getting Started
Learn about routes, navigation, and transitions for apps written using the Flutter cross-platform framework from Google. By Filip Babić.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Flutter Navigation: Getting Started
15 mins
What’s better than an app with one screen? Why, an app with two screens, of course! :]
Navigation is a key part of the user experience for any mobile application. Due to the limited screen real estate on mobile devices, users will constantly be navigating between different screens. For example, from a list to a details screen, from a shopping cart to a checkout screen, from a menu into a form, and many other cases. Good navigation helps your users find their way around and get a sense of the breadth of your app.
The iOS navigation experience is often built-around a UINavigationController, which uses a stack-based approach to shifting between screens. On Android, the Activity stack is the central means to shift a user between different screens, although the use of Jetpack Navigation with a single-Activity architecture is a new and recommended approach. Unique transitions between screens in these stacks can help give your app a unique feel.
Just like the native SDKs, cross-platform development frameworks such as Flutter must provide a means for your app to switch between screens. In most cases, you’ll want the navigation approach to be consistent with what the users of each platform have come to expect – to have a native experience.
In this tutorial, you’ll see how Flutter implements navigation between the different screens of a cross-platform app, by learning about:
- Routes and navigation
- Popping off the stack
- Returning a value from a route
- Custom navigation transitions
If you’re new to Flutter, please check out our Getting Started with Flutter tutorial to see the basics of working with Flutter.
Getting Started
You can download the starter project for this tutorial from the Download Materials button at the top or bottom of the page.
This tutorial will be using VS Code, with the Flutter extension. You can also use IntelliJ IDEA or Android Studio, or work with a text editor of your choice with Flutter at the command line.
Open the starter project in VS Code by choosing File ▸ Open and finding the root folder of the starter project zip file:
VS Code will prompt you to fetch the packages you need for the project, so go ahead and do so:
Once the project is open in VS Code, hit F5 to build and run the starter project. If VS Code prompts you to choose an environment to run the app in, choose “Dart & Flutter”:
Here is the project running in the iOS Simulator:
And here it is running on an Android emulator:
The “debug” banner you see is due to the fact that you’re running a debug build of the app, pretty neat!
The starter app shows the list of members in a GitHub organization. In this tutorial, you’ll navigate from this first screen to a new screen for each member.
Creating a Widget to Navigate To
You first need to create a screen to navigate to each member’s details. Elements of a Flutter UI take the form of UI widgets, so you’ll have to create a member widget.
First, right-click on the lib folder in the project, choose New File. Then create a new file named memberwidget.dart:
Add import statements and a StatefulWidget
subclass with the name MemberWidget
to the new file:
import 'package:flutter/material.dart';
import 'member.dart';
class MemberWidget extends StatefulWidget {
// 1
final Member member;
MemberWidget(this.member) {
// 2
if (member == null) {
throw ArgumentError(
"member of MemberWidget cannot be null. Received: '$member'");
}
}
// 3
@override
createState() => MemberState(member);
}
Here you:
- Add a
Member
property for the widget. - Make sure that the
member
argument is not-null in the widget constructor. - Use a
MemberState
class for the state, passing along aMember
object to theMemberState
.
Add the MemberState
class above MemberWidget
in the same file:
class MemberState extends State<MemberWidget> {
final Member member;
MemberState(this.member);
}
Here, you’ve given MemberState
a Member
property and a constructor.
Each widget must override the build()
method, so add the override to MemberState
now:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(member.login),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Image.network(member.avatarUrl)));
}
You’re creating a Scaffold
, a material design container, which holds an AppBar
and a Padding
with a child Image
for the member avatar.
With the member screen all set up, you now have somewhere to navigate to! :]
Navigation using Routes
Navigation in Flutter is centered around the idea of routes.
Routes are similar in concept to the routes that you would use in a REST API, where each route is relative to some root. The widget main()
acts like the root in your app (“/”) and all other routes are relative to that one.
One way to use routes is with PageRoute
. Since you’re working with a Flutter MaterialApp, you’ll use the MaterialPageRoute
.
Add an import to the top of ghflutterwidget.dart to pull in the member widget:
import 'memberwidget.dart';
Next, add a private method _pushMember()
to GHFlutterState
in the same file:
_pushMember(Member member) {
Navigator.push(context,
MaterialPageRoute(builder: (context) => MemberWidget(member)));
}
Here, you’re using Navigator
to push a new MaterialPageRoute
onto the stack, and you build the MaterialPageRoute
using a MemberWidget
.
Now you need to call _pushMember()
when a user taps on a row in the list of members. You can do so by updating _buildRow()
in GHFlutterState
and adding an onTap
attribute to the ListTile
:
Widget _buildRow(int i) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: ListTile(
title: Text("${_members[i].login}", style: _biggerFont),
leading: CircleAvatar(
backgroundColor: Colors.green,
backgroundImage: NetworkImage(_members[i].avatarUrl)
),
// Add onTap here:
onTap: () {
_pushMember(_members[i]);
},
)
);
}
Now, when a row is tapped, your new method, _pushMember()
, is called with the member that was tapped. This in turn will open up the details screen.
Hit F5 to build and run the app. Tap a member row and you should see the member detail screen come up:
And here’s the member screen running on iOS:
Notice that the back button on Android has the Android style and the back button on iOS has the iOS style. And also notice that the transition style when switching to the new screen matches the platform’s transition style.
Tapping the back button takes you back to the member list, but what if you want to manually trigger going back from your own button in the app?