Flutter Navigation

Summary: in this tutorial, you’ll learn about flutter navigation to navigate from one screen to another and back.

Introduction to the Flutter navigation

Typically, apps contain multiple screens for displaying different information. For example, an E-commerce app may have a screen that displays a list of products. When the user taps a product, a new screen displays the product details.

Flutter navigation manages the screens as a stack and shows the screen that is on top of the stack.

Stack

A stack is a data structure that serves as a collection of items with two main operations:

  • Push – add an item to the stack.
  • Pop – remove the most recently added item from the stack.

The order in which an item is added to or removed from the stack is known as last in, first out, or LIFO in short.

A real-life example of a stack database structure is a pile of books or a deck of cards.

Navigator

Flutter navigation works like a stack of screens. In Flutter, screens and pages are often called routes, which are widgets.

Flutter uses the Navigator object to navigate from one route to another. The Navigator object is like a stack of routes, which has two main methods:

  • push() – navigate to a new route by adding a route to the stack.
  • pop() – remove the current route from the stack.

Flutter navigation example

The following example shows how to use the Navigator object to navigate to a new route and back:

import 'package:flutter/material.dart';

void main() {
  runApp(
      const MaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Flutter Navigation',
        home: HomeScreen(),
    )
  );
}

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home screen'),
      ),
      body: Center(
        child: ElevatedButton(
          child: const Text('Go to the detail screen'),
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => const DetailScreen()),
            );
          },
        ),
      ),
    );
  }
}

class DetailScreen extends StatelessWidget {
  const DetailScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Detail screen'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: const Text('Go back!'),
        ),
      ),
    );
  }
}
Code language: Dart (dart)

How it works.

First, create two screens: HomeScreen and DetailScreen.

Second, the HomeScreen has a button. When the button is pressed, call the push() method of the Navigator object to navigate to the new route.

onPressed: () {
  Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => const SecondScreen()),
  );
}Code language: Dart (dart)

The push() method accepts the first argument as the current BuildContext and the second argument as a MaterialPageRoute object.

The MaterialPageRoute object specifies the new route to navigate to.

Third, the DetailScreen also has a button. When the button is pressed, go back to the HomeScreen by calling the pop() method of the Navigator object:

Navigator.pop(context);Code language: Dart (dart)

The pop() method accepts a context of the current BuildContext.

Sending data to the new route

The following example illustrates how to send a string from the HomeScreen to DetailScreen:

import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(
    debugShowCheckedModeBanner: false,
    title: 'Flutter Navigation',
    home: HomeScreen(),
  ));
}

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home screen'),
      ),
      body: Center(
        child: ElevatedButton(
          child: const Text('Go to the detail screen'),
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => const DetailScreen(
                    message: 'This is a message from the home screen'),
              ),
            );
          },
        ),
      ),
    );
  }
}

class DetailScreen extends StatelessWidget {
  final String message;

  const DetailScreen({super.key, required this.message});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Detail screen'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(message),
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context);
              },
              child: const Text('Go back!'),
            ),
          ],
        ),
      ),
    );
  }
}Code language: Dart (dart)

How it works.

First, add the message property to the DetailScreen and a constructor that accepts a string.

Second, add a Text widget to display the message property.

Third, when calling the push() method of the Navigator object, pass a string to the DetailScreen constructor.

Sending data back to the previous route

The following example illustrates how to pass data from the DetailScreen back to the HomeScreen:

import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(
    debugShowCheckedModeBanner: false,
    title: 'Flutter Navigation',
    home: HomeScreen(),
  ));
}

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home screen'),
      ),
      body: Center(
        child: ElevatedButton(
          child: const Text('Go to the detail screen'),
          onPressed: () async {
            var message = await Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => const DetailScreen(
                    message: 'This is a message from the home screen'
                ),
              ),
            );
            print(message);
          },
        ),
      ),
    );
  }
}

class DetailScreen extends StatelessWidget {
  final String message;

  const DetailScreen({super.key, required this.message});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Detail screen'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(message),
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context, 'This is a message from the Detail screen');
              },
              child: const Text('Go back!'),
            ),
          ],
        ),
      ),
    );
  }
}Code language: Dart (dart)

First, pass a string to the second argument of the pop() method of the Navigator object from the DetailScreen:

onPressed: () {
	Navigator.pop(
		context, 
		'This is a message from the Detail screen'
	);
}Code language: Dart (dart)

Second, change the onPressed function to an async function because we’ll use the await keyword inside it.

The push() method returns a Future object therefore we use the await keyword to wait for the data future to be ready before getting the return value.

For the sake of demonstration, we print out the returned string.

onPressed: () async {
	var message = await Navigator.push(
		context,
                MaterialPageRoute(builder: (context) => const DetailScreen(message: 'This is a message from the home screen')),
	);
	print(message);
}Code language: Dart (dart)

Summary

  • Use Navigator object to navigate from one route to another.
  • Use push() method of the Navigator object to navigate to a new route.
  • Use pop() method of the Navigator object to go back to the previous route.
Was this tutorial helpful ?