arrow_back

Implementing Page Navigation in a Flutter Application

Join Sign in
Test and share your knowledge with our community!
done
Get access to over 700 hands-on labs, skill badges, and courses

Implementing Page Navigation in a Flutter Application

Lab 1 hour 30 minutes universal_currency_alt 1 Credit show_chart Introductory
Test and share your knowledge with our community!
done
Get access to over 700 hands-on labs, skill badges, and courses

GSP1012

Google Cloud self-paced labs logo

Flutter is Google's UI toolkit for building beautiful, natively compiled applications for mobile, web, and desktop from a single codebase. Flutter works with existing code, is used by developers and organizations around the world, and is free and open source.

In this lab, you will create a Flutter app using generated template code. The basic Flutter interface provides a simple example to get started programming in Flutter.

The Flutter interface displayed on a mobile phone screen

What you'll learn

  • How to write a Flutter app that looks natural on iOS, Android, and the web
  • Basic structure of a Flutter app
  • Using multiple pages
  • Using hot reload for a quicker development cycle

Prerequisites

Based on the content, it is recommended to have some familiarity with:

  • Flutter
  • Dart

Task 1. Open the Code Server Editor

In this lab, you will use a custom editor that includes the Flutter and Dart extensions. From the initial lab panel:

The Lab Details panel displaying the IDE and Live Server links

  1. Copy the Flutter Editor address displayed.
  2. Paste the Editor address into a Browser tab.

Task 2. Creating a Flutter template

In this section create a Flutter Web application called first_app.

  1. Click the hamburger button (i.e. Left hand side, three horizontal lines Navigation menu icon).
  2. Open a Terminal within the browser by selecting New Terminal.

The navigation path to the New Terminal option in the Terminal submenu of the expanded naviagtion menu

  1. In the terminal enter the following command:
flutter create first_app
  1. Move to the first_app directory:
cd first_app
  1. Close the terminal window:
exit

The first_app directory and template code have now been created.

Task 3. Opening the new app

In this section explore the Flutter Web application called first_app.

  1. Open the folder first_app.
  2. Acknowledge the on-screen notifications.

At this point you will have the Flutter application open in the current workspace.

Task 4. Running the Flutter web application

In this section run the Flutter Web application from the command line.

  1. In the editor, open a Terminal.
  2. Ensure the terminal directory is set to first_app.
  3. Run the Flutter web server:
fwr
  1. The running web server should look similar to below:

The running web server output

  1. Copy the Flutter Live Server address from the lab Panel.

  2. Paste the address into a new browser tab.

The browser will render the web application e.g.

The Flutter Demo Home Page displayed on a mobile phone screen

Note: Rendering of the web application can take up to ten seconds. The view will show the application based on the code in the editor.

Feel free to interact with the running application.

Task 5. Adding boilerplate code

In this section, replace the Flutter starter code with the example for this lab.

  1. Replace the contents of lib\main.dart with the code below:
import 'package:flutter/material.dart'; // TODO: Embedded List class GoogleProducts { final List<String> items = [ 'Cloud Functions', 'App Engine', 'Kubernetes Engine', 'Compute Engine', 'Bare Metal', 'Pre-emtible VMs', 'Shielded VMs', 'Sole-tenet Nodes', 'VMWare Engine', 'Cloud Firestore', 'Cloud Storage', 'Persistent Disk', 'Local SSD', 'Cloud Bigtable', 'Cloud Firestore', 'Cloud Memorystore', 'Cloud Spanner', ]; } void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { const title = 'Google Products'; return const MaterialApp( title: title, debugShowCheckedModeBanner: false, home: ProductHomeWidget(title), ); } } // TODO: ProductHomeWidget class ProductHomeWidget extends StatelessWidget { final String title; const ProductHomeWidget(this.title, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: AppBar( backgroundColor: Colors.transparent, elevation: 0, iconTheme: const IconThemeData( color: Colors.grey, //change your color here ), actions: const [ AppBarActionsShare(), ], title: Text(title, style: const TextStyle(color: Colors.black)), ), body: ProductListView(), // TODO: Add Drawer // drawer: const MyDrawerWidget(), ); } } // TODO: AppBarLeading class AppBarLeading extends StatelessWidget { const AppBarLeading({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return const IconButton( icon: Icon( Icons.menu, ), onPressed: null, ); } } // TODO: AppBarActionsShare class AppBarActionsShare extends StatelessWidget { const AppBarActionsShare({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return IconButton( icon: const Icon( Icons.share, ), onPressed: () { const snackBar = SnackBar(content: Text('You selected the Action: Share')); ScaffoldMessenger.of(context).showSnackBar(snackBar); }); } } // TODO: Enable Drawer class MyDrawerWidget extends StatelessWidget { const MyDrawerWidget({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Drawer( child: ListView( children: const [ DrawerHeader( child: Icon(Icons.flutter_dash, size: 35), ), ], ), ); } } // TODO: ProductListView class ProductListView extends StatelessWidget { final googleProducts = GoogleProducts(); ProductListView({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return ListView.builder( itemCount: googleProducts.items.length, itemBuilder: (context, index) { return ProductListTile(googleProducts.items[index]); }, ); } } // TODO: ProductListTile class ProductListTile extends StatelessWidget { final String? productLabel; const ProductListTile(this.productLabel, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { return ListTile( title: Text('$productLabel', style: const TextStyle(color: Colors.black)), subtitle: const Text('SubTitle', style: TextStyle(color: Colors.black)), leading: const Icon(Icons.info, color: Colors.black), // When the child is tapped, show a snackbar. onTap: () { Navigator.push( context, MaterialPageRoute(builder: (context) => const MyDetails()), ); }, ); } } // TODO: Add a details page class MyDetails extends StatelessWidget { final title = 'Details Page'; const MyDetails({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, body: DefaultTabController( length: 4, child: Scaffold( appBar: AppBar( backgroundColor: Colors.transparent, elevation: 0, iconTheme: const IconThemeData( color: Colors.grey, //change your color here ), title: Text(title, style: const TextStyle(color: Colors.grey)), actions: const [ AppBarActionsShare(), ], // TODO: Add TabBar // bottom: const TabBar( // indicatorColor: Colors.black, // tabs: [ // Tab( // icon: Icon(Icons.home, color: Colors.grey), // child: Text('Overview', // style: TextStyle( // color: Colors.grey, fontWeight: FontWeight.bold)), // ), // Tab( // icon: Icon(Icons.favorite, color: Colors.grey), // child: Text('Docs', // style: TextStyle( // color: Colors.grey, fontWeight: FontWeight.bold)), // ), // Tab( // icon: Icon(Icons.list, color: Colors.grey), // child: Text('Information', // style: TextStyle( // color: Colors.grey, fontWeight: FontWeight.bold)), // ), // Tab( // icon: Icon(Icons.info, color: Colors.grey), // child: Text('Other', // style: TextStyle( // color: Colors.grey, fontWeight: FontWeight.bold)), // ), // ], // ), ), // TODO: Add TabBarView // body: const TabBarView( // children: [ // SizedBox( // child: Center( // child: Text('Tab Page 1'), // ), // ), // SizedBox( // child: Center( // child: Text('Tab Page 2'), // ), // ), // SizedBox( // child: Center( // child: Text('Tab Page 3'), // ), // ), // SizedBox( // child: Center( // child: Text('Tab Page 4'), // ), // ), // ], // ), ), ), ); } }
  1. Perform a hot restart to review the changes to the Flutter user interface.

  2. After updating lib\main.dart with the boilerplate code, refresh the application.

The Flutter app should now look similar to the image below:

A mobile phone screen displaying a list of subtitles below the Google Products title

In the next section, we outline the application we will build in this lab.

Task 6. Designing our application

In this section use widgets to enhance our basic two screen application.

  1. First we will update the details page to incorporate a TabView. A list view to tab view illustration

From the above sketch we note that our application uses the following types of widgets:

Widget Description
TabView Tabbed page view for information
RichText Enhanced text for displaying information
Image Image display
  1. Then we will add a drawer navigation to provide quick access to information.

A drawer navigation illustration

From the above sketch we note that our application uses the following types of widgets:

Widget Description
Drawer Application navigation
Icon Add an avatar to the Drawer

In the next section, we discuss Adding the TabView to the application.

Task 7. Including a TabView

Update the TabView setting to reference in the function MyDetails.

  1. Find the following line(s) and uncomment the code (i.e. remove the // characters):
// TODO: Add TabBar // bottom: const TabBar( // indicatorColor: Colors.black, // tabs: [ // Tab( // icon: Icon(Icons.home, color: Colors.grey), // child: Text('Overview', // style: TextStyle( // color: Colors.grey, fontWeight: FontWeight.bold)), // ), // Tab( // icon: Icon(Icons.favorite, color: Colors.grey), // child: Text('Docs', // style: TextStyle( // color: Colors.grey, fontWeight: FontWeight.bold)), // ), // Tab( // icon: Icon(Icons.list, color: Colors.grey), // child: Text('Information', // style: TextStyle( // color: Colors.grey, fontWeight: FontWeight.bold)), // ), // Tab( // icon: Icon(Icons.info, color: Colors.grey), // child: Text('Other', // style: TextStyle( // color: Colors.grey, fontWeight: FontWeight.bold)), // ), // ], // ),

Your code should now look like this:

// TODO: Add TabBar bottom: const TabBar( indicatorColor: Colors.black, tabs: [ Tab( icon: Icon(Icons.home, color: Colors.grey), child: Text('Overview', style: TextStyle( color: Colors.grey, fontWeight: FontWeight.bold)), ), Tab( icon: Icon(Icons.favorite, color: Colors.grey), child: Text('Docs', style: TextStyle( color: Colors.grey, fontWeight: FontWeight.bold)), ), Tab( icon: Icon(Icons.list, color: Colors.grey), child: Text('Information', style: TextStyle( color: Colors.grey, fontWeight: FontWeight.bold)), ), Tab( icon: Icon(Icons.info, color: Colors.grey), child: Text('Other', style: TextStyle( color: Colors.grey, fontWeight: FontWeight.bold)), ), ], ),
  1. Perform a hot restart to review the changes to the Flutter user interface.
Note: TabBar provides a tab interface in your application. In the above code we add four tabs that will be used to show diffferent information. The tabs are functional and you can switch between them.

A mobile phone screen diaplying the following tabs on the Details page: Overview, Docs, Information, and Other

At this point you will be able to move between the pages using the onscreen navigation.

In the next section, we add a TabBarView to the application.

Task 8. Adding a TabBarView

Update the TabBarView setting referenced in the function MyDetails.

  1. Find the following line(s) and uncomment the code (i.e. remove the // characters):
// body: const TabBarView( // children: [ // SizedBox( // child: Center( // child: Text('Tab Page 1'), // ), // ), // SizedBox( // child: Center( // child: Text('Tab Page 2'), // ), // ), // SizedBox( // child: Center( // child: Text('Tab Page 3'), // ), // ), // SizedBox( // child: Center( // child: Text('Tab Page 4'), // ), // ), // ], // ),

Your code should now look like this:

body: const TabBarView( children: [ SizedBox( child: Center( child: Text('Tab Page 1'), ), ), SizedBox( child: Center( child: Text('Tab Page 2'), ), ), SizedBox( child: Center( child: Text('Tab Page 3'), ), ), SizedBox( child: Center( child: Text('Tab Page 4'), ), ), ], ),
  1. Perform a hot restart to review the changes to the Flutter user interface.
Note: TabBarView provides a view per tab defined. As the application has four tabs, we create four TabBarViews that represent a unique page for displaying tab information.

A mobile phone screen open on the Overview tabbed page which displays the follwoing text: Tab Page 1

Now as the tabs are selected, the associated page view is displayed

In the next section, we add a Drawer to perform application navigation.

Task 9. Adding a drawer

Update the main menu icon to open a custom drawer in ProductHomeWidget.

  1. Find the following line(s) and uncomment the code (i.e. remove the // characters):
drawer: const MyDrawerWidget(),

Your code should now look like this:

class ProductHomeWidget extends StatelessWidget { final String title; const ProductHomeWidget(this.title, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: AppBar( backgroundColor: Colors.transparent, elevation: 0, iconTheme: const IconThemeData( color: Colors.grey, //change your color here ), actions: const [ AppBarActionsShare(), ], title: Text(title, style: const TextStyle(color: Colors.black)), ), body: ProductListView(), // TODO: Add Drawer drawer: const MyDrawerWidget(), ); } }
  1. Perform a hot restart to review the changes to the Flutter user interface.
Note: Selecting the main menu now opens the Drawer. However it doesnt link to any of the existing pages as we havent told it to.

A mobile phone screen displaying a blank page with an icon

In the next section, update the Drawer to route to the home page.

Task 10. Routing to Home

Update the custom drawer in MyDrawerWidget Route the Home drawer item to MyApp page.

  1. Update the DrawerHeader and add a ListTile in the MyDrawerWidget build method:
children: [ const DrawerHeader( child: Icon(Icons.flutter_dash, size: 35), ), ListTile( leading: const Icon(Icons.home), title: const Text('Home'), onTap: () { Navigator.of(context).push( MaterialPageRoute(builder: (context) => const MyApp()), ); }, ),

Your code should now look like this:

class MyDrawerWidget extends StatelessWidget { const MyDrawerWidget({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Drawer( child: ListView( children: [ const DrawerHeader( child: Icon(Icons.flutter_dash, size: 35), ), ListTile( leading: const Icon(Icons.home), title: const Text('Home'), onTap: () { Navigator.of(context).push( MaterialPageRoute(builder: (context) => const MyApp()), ); }, ), ], ), ); } }
  1. Perform a hot restart to review the changes to the Flutter user interface.

A mobile phone screen displaying a blank page with an icon and a Home button

Note: Now when the home option is selected the Home page will open.

In the next section, update the Drawer to route to the Details page.

Task 11. Routing to Details

Update the custom drawer in MyDrawerWidget and route the other Drawer items to the MyDetails page.

  1. Add the following line(s) in the MyDrawerWidget build method:
onTap: () { Navigator.of(context).push( MaterialPageRoute(builder: (context) => const MyDetails()), ); },

Your code should now look like this:

class MyDrawerWidget extends StatelessWidget { const MyDrawerWidget({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Drawer( child: ListView( children: [ const DrawerHeader( child: Icon(Icons.flutter_dash, size: 35), ), ListTile( leading: const Icon(Icons.home), title: const Text('Home'), onTap: () { Navigator.of(context).push( MaterialPageRoute(builder: (context) => const MyApp()), ); }, ), ListTile( leading: const Icon(Icons.info), title: const Text('Details'), onTap: () { Navigator.of(context).push( MaterialPageRoute(builder: (context) => const MyDetails()), ); }, ), ], ), ); } }
  1. Perform a hot restart to review the changes to the Flutter user interface.

A mobile phone screen displaying a blank page with an icon, Home button, and Details button.

Note: Now when the other options are selected the Details page will open.

Click Check my progress to verify the objective. Assess my progress

Congratulations!

You have successfully completed the lab and demonstrated your knowledge of Flutter. Over the course of this lab, you have performed the following tasks:

  • Used a TabBar and TabBarView widget
  • Added a Drawer to improve navigation
  • Learned to route to specific pages

This self-paced lab is part of the Flutter Essentials quest. A quest is a series of related labs that form a learning path. Completing this quest earns you a badge to recognize your achievement. You can make your badges public and link to them in your online résumé or social media account. Enroll in this quest to get immediate credit for completing this lab.
See other available quests.

Manual Last Updated September 19, 2022

Lab Last Tested January 17, 2022

Copyright 2024 Google LLC All rights reserved. Google and the Google logo are trademarks of Google LLC. All other company and product names may be trademarks of the respective companies with which they are associated.