Mobile apps reveal the contents via “screen”. In Android, these screens call Activity while in IOS these screens call ViewController. In Flutter, these elements are called “routes” and they’re managed by a Navigator. The navigator manages a stack of Screen (Route) objects and provides methods for managing the stack, like Navigator.push and Navigator.pop.
Android provides a back button that will allow the user to navigate back to earlier Activity in your application’s stack. On IOS AppBar can automatically add a back button for user navigation.
As you can see, the new screen push, revealing the app’s home page, with the Navigator’s push method:

Pressing the back button causes Navigator.pop to be called. On Android, pressing the system back button does the same thing.
First, you need a simple way to represent User. Create a class that contains two pieces of data: the UserName and Password.
class User {
final String userName;
final String password;
User(this.userName, this.password);
}
The MaterialApp‘s home becomes the route at the bottom of the Navigator‘s stack. It is what you see when the app is launched.
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Navigator Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: LoginPage(title: 'Navigator Home Page'),
);
}
}
Create the First Screen
First, create a login screen with two TextField and RaisedButton. Launches the Home Screen when it’s tapped. Waits for the HomeScreen to return a result.
class LoginPage extends StatelessWidget {
final String title;
TextEditingController userNameController = TextEditingController();
TextEditingController passwordController = TextEditingController();
LoginPage({Key key, this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 256,
margin: const EdgeInsets.only(bottom: 8),
child: TextField(
decoration: InputDecoration(
hintText: 'Enter user name', labelText: 'User Name'),
controller: userNameController,
),
),
Container(
width: 256,
margin: const EdgeInsets.only(bottom: 8),
child: TextField(
obscureText: true,
decoration: InputDecoration(
hintText: 'Enter password', labelText: 'Password'),
controller: passwordController,
),
),
RaisedButton(
child: Text("Login"),
onPressed: () {
_navigateHome(context);
},
)
],
),
),
);
}
_navigateHome(BuildContext context) async {
....
}
}
To push a new screen on the stack, create an instance of MaterialPageRoute with a builder function that creates whatever you want to appear on the screen. You put the data that you want to send as a parameter in its constructor.
_navigateHome(BuildContext context) async {
User user = new User(userNameController.text, passwordController.text);
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomePage(
user: user,
)));
print(result);
}
The value can be returned via the pop method’s result parameter. Methods that push a route return a Future. The Future resolves when the route is popped and the Future‘s value is the pop method’s result parameter.
Create the Second Screen
Now, build a Home screen that contains one button. When a user taps a button, that app closes the Home screen. Make the HomeScreen constructor take a parameter for the type of data that you want to send to it. In this particular example, the data is defined to be a User value and is set here with this.user.
class HomePage extends StatelessWidget {
final User user;
HomePage({Key key, this.user}) : super(key: key);
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text("Home Page"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context, true);
},
child: Text('Log Out ${user.userName}'),
),
),
);
}
}
If we wanted to ask the user to press ‘Logout’ to confirm we could await the result of Navigator.push.