GSP1012
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.
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:
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:
- Copy the Flutter Editor address displayed.
- 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.
- Click the hamburger button (i.e. Left hand side, three horizontal lines ).
- Open a Terminal within the browser by selecting New Terminal.
- In the terminal enter the following command:
flutter create first_app
- Move to the first_app directory:
cd first_app
- 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.
- Open the folder
first_app
.
- 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.
- In the editor, open a Terminal.
- Ensure the terminal directory is set to
first_app
.
- Run the Flutter web server:
fwr
- The running web server should look similar to below:
-
Copy the Flutter Live Server address from the lab Panel.
-
Paste the address into a new browser tab.
The browser will render the web application e.g.
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.
- 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'),
// ),
// ),
// ],
// ),
),
),
);
}
}
-
Perform a hot restart
to review the changes to the Flutter user interface.
-
After updating lib\main.dart
with the boilerplate code, refresh the application.
The Flutter app should now look similar to the image below:
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.
- First we will update the details page to incorporate a TabView.
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 |
- Then we will add a drawer navigation to provide quick access to information.
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
.
- 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)),
),
],
),
- 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.
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
.
- 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'),
),
),
],
),
- 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.
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
.
- 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(),
);
}
}
- 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.
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.
- 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()),
);
},
),
],
),
);
}
}
- Perform a
hot restart
to review the changes to the Flutter user interface.
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.
- 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()),
);
},
),
],
),
);
}
}
- Perform a
hot restart
to review the changes to the Flutter user interface.
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 2025 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.