Flutter Application Development Book
Flutter Application Development Book
Flutter Application
Development
Android ATC
i
FlutterTM Application Development
Because this book is being published at a time of a global pandemic, this book
is dedicated to all front-line workers who putting their lives at risk battling
COVID-19 to save our lives.
ii
FlutterTM Application Development AFD-200
ISBN: 978-0-9900143-9-3
Information in this book, including URL and other Internet Web site references, is
subject to change without notice. Complying with all applicable copyright laws, no
part of this document may be reproduced, stored in or introduced into a retrieval
system, or transmitted in any form or by any means (electronic, mechanical,
photocopying, recording, or otherwise), or for any purpose, without the express
written permission from Android ATC.
Android ATC is not responsible for webcasting or any other form of transmission
received from any linked site.
Android ATC is providing these links to you only as a convenience, and the inclusion
of any link does not imply endorsement of Android ATC of the site or the products
contained therein.
Android ATC may have patents, patent applications, trademarks, copyrights, or other
intellectual property rights covering subject matter in this document. As expressly
provided in any written license agreement from Android ATC, the furnishing of this
document does not give you any license to these patents, trademarks, copyrights, or
other intellectual property.
Flutter application development is a detailed guide that provides the basics to build
Flutter applications. It is a combination of theoretical lessons and practical labs that
covers skills and knowledge every Flutter developer should learn before starting the
development of real-world applications.
All lessons and their lab exercises in this book were built to comply with the latest
versions of Flutter SDK and Android Studio IDE. Since the update of both Flutter SDK
and Android Studio is a continuous process, it is highly possible that any of these
components has already been updated by the time you start your training using this
iii
FlutterTM Application Development
book. If this is the case, you might notice some minor difference in the lab steps and
the screenshots provided, depending on how major an update has been. Updates
neither make the lessons outdated nor the labs incorrect. It is only impractical to
release a new version of the book for every update.
Android ATC Training team continuously works on providing the most up to date labs
and code samples. Nonetheless, we would like to apologize in advance in case any
lab step or screenshot was inaccurate.
Exam
You can examine your knowledge on the content of this book by taking the online
exam AFD-200 through Pearson-VUE testing centers worldwide. Passing this exam
grants the examinee the title: “Flutter Certified Application Developer. For more
information, visit:
http:// www.pearsonvue.com/androidatc
Or, you may schedule your exam at any Android ATC authorized training center
worldwide. Check Android ATC web site for more information.
Trademark Acknowledge:
All terms mentioned in this book that are known to be trademarks or service marks
have been appropriately capitalized. The use of a term in this book should not be
regarded as affecting the validity of any trademark or service mark.
iv
FlutterTM Application Development AFD-200
Feedback Information:
As Android ATC, our goal is to create in-depth technical books of the highest quality
and value. Each book is crafted with care and precision, undergoing rigorous
development that involves the unique expertise of members from professional
technical community.
v
FlutterTM Application Development
Table of Contents
Lesson 1: Introduction to Flutter and Dart Programming Language
Introduction............................................................................................................................ 1-2
Importance of Flutter............................................................................................................ 1-2
Introduction to Dart................................................................................................................ 1-3
Writing Dart code................................................................................................................... 1-3
DartPad................................................................................................................................... 1-4
Installing Dart SDK................................................................................................................. 1-4
IntelliJ IDEA ........................................................................................................................... 1-10
Lab 1: Installing Dart IDE and Writing Dart Program........................................................... 1-12
Installing IntelliJ IDEA....................................................................................................... 1-13
Creating a Dart Project Using IntelliJ IDEA...................................................................... 1-25
Using DartPad................................................................................................................... 1-29
vi
FlutterTM Application Development AFD-200
vii
FlutterTM Application Development
viii
FlutterTM Application Development AFD-200
ix
FlutterTM Application Development
Lesson 9: Firebase
Introduction............................................................................................................................ 9-2
What is the JSON ?................................................................................................................ 9-3
How does Firebase Database work?..................................................................................... 9-4
Firebase authentication (Signup and Login to Flutter App)................................................ 9-5
Configure Your App to use Firebase Services...................................................................... 9-17
Adding Firebase to your Android App.............................................................................. 9-19
Adding Firebase to your iOS App..................................................................................... 9-26
Configuring Firebase Authentication.................................................................................... 9-33
Login to an App Using Firebase User Accounts.............................................................. 9-46
Logout Configuration........................................................................................................ 9-48
Firebase Database................................................................................................................. 9-53
Which database is right for your project?........................................................................ 9-53
Real Time Database.......................................................................................................... 9-54
Cloud Firestore.................................................................................................................. 9-63
Lab 9 : Create a User Profile Interface using Firebase........................................................ 9-72
x
FlutterTM Application Development AFD-200
xi
Introduction to Dart AFD-200
Introduction............................................................................................................................ 1-2
Importance of Flutter............................................................................................................ 1-2
Introduction to Dart................................................................................................................ 1-3
Writing Dart code................................................................................................................... 1-3
DartPad................................................................................................................................... 1-4
Installing Dart SDK................................................................................................................. 1-4
IntelliJ IDEA............................................................................................................................ 1-10
Lab 1: Installing Dart IDE and Writing Dart Program.......................................................... 1-12
Installing IntelliJ IDEA....................................................................................................... 1-13
Creating a Dart Project Using IntelliJ IDEA...................................................................... 1-25
Using DartPad................................................................................................................... 1-29
1-1
Flutter ™ Application Development
Introduction
Flutter is an open-source user interface software development kit (app SDK )
created by Google. It is for building high-performance, high-fidelity apps for iOS,
Android, and web from a single codebase.
The purpose of this course is to enable developers create high-performance and
attractive apps that feel natural on iOS & Android devices.
Flutter, is used by companies around the world including Alibaba, Capital One, and
Groupon for apps that touch hundreds of millions of users.
Importance of Flutter
Because any developer or anyone who wants to learn about mobile development
can now build native Android and iOS apps with one codebase ONLY! This means,
instead of having to learn Objective-C or Swift to build iOS apps, and Java or Kotlin
to build Android apps, you can now use Flutter Mobile Development Framework
to build apps that run natively on both iOS and Android devices using the Dart
Programming Language.
This course is designed for you to start learning the Dart Programming Language
( which is used by Flutter SDK to build native iOS and Android Apps), Flutter
1-2
Introduction to Dart AFD-200
o Do more with less code, even on a single OS, with a modern, expressive
language, and a declarative approach.
o Prototype and iterate easily where you can change your code and reload
it as your app runs (hot reload feature) as you will see in the next lessons.
Also, Flutter fixes crashes and continue debugging from where the app is
left off.
2- Create beautiful, highly-customized user experiences (UI):
o Benefit from a rich set of Material Design and Cupertino (iOS-flavor) widgets
built using Flutter's own framework.
Introduction to Dart
Dart is an object-oriented programming language developed by Google. It is an
open-source, scalable programming language, with robust libraries and runtimes, for
building web, server, and mobile apps.
1- Dart SDK
The Dart SDK has the libraries and command-line tools that you need to develop
Dart web, command-line, mobile, and server apps.
1-3
Flutter ™ Application Development
The Dart SDK has the libraries and command-line tools that you need to write
and run Dart code. The Dart SDK includes a lib directory for the Dart libraries and
a bin directory that has the command-line tools. In the next topics of this lesson,
you will know more about installing and configuring Dart SDK.
2- Dart IDE
We use Dart IDEs (integrated Development Environment) to create a Dart program ,
where these IDEs include Dart plugins which are used to make a connection between
the IDE graphical user interface software and the Dart SDK.
The following are some examples of Dart IDEs which you can use to write Dart code:
•• IntelliJ IDEA
•• Android Studio
•• Visual Studio
DartPad
DartPad is an open-source tool that lets you work with the Dart language in any
modern web browser. It is a great, no-download-required way to learn Dart syntaxes
and to experiment with Dart language features.
To test DartPad, go to : https://dartpad.dev , then you can test all Dart syntaxes.
In lab 1 at the end of this lesson, you will test DartPad web site and check how you
can write Dart commands using your web browser without the need to install any
software on your computer and whatever operating system your computer has.
When you later use Flutter SDK to create a mobile app, you don't need to
install Dart SDK or Dart plugins to any IDE such as Android Studio or IntelliJ
IDEA because Flutter SDK already includes Dart SDK. Also, Flutter plugins
.already include Dart plugins
https://dart.dev/get-dart.
1-4
Introduction to Dart AFD-200
In this exercise, you will install Dart SDK using Microsoft Windows operating
system. For other operating systems , you will almost have the same installation
wizard.
2- Select the operating system which your computer has, Windows, Linux or Mac.
4- Scroll down, and as illustrated in the below figure, click : Dart SDK installer for
Windows .
1-5
Flutter ™ Application Development
7- Click this file, select Run, and you will get the following installation wizard:
1-6
Introduction to Dart AFD-200
10- Keep the default path as illustrated in the below image, then click Next
1-7
Flutter ™ Application Development
1-8
Introduction to Dart AFD-200
1-9
Flutter ™ Application Development
IntelliJ IDEA
IntelliJ IDEA is a Java integrated development environment for developing computer
software. It is developed by JetBrains,
IntelliJ IDEA is free software used to develop Java, Kotlin, Dart, and other
programming languages.
The first three lessons of this course discuss the fundamentals of Dart
programming language. In these three lessons, you will learn how to write small
separate Dart programs to become familiar with the Dart syntaxes - which you will
use later in writing the code to create Flutter mobile applications for Android and
iOS devices.
1-10
Introduction to Dart AFD-200
We recommend using IntelliJ IDEA as a compiler software to create and run pure
Dart programs.
In the lab of this lesson, you will install IntelliJ IDEA step by step and use it to create
and run a Dart program.
1-11
Flutter ™ Application Development
Lab 1
1-12
Introduction to Dart AFD-200
2- Under Community, Click DOWNLOAD button. The download process will start to
download IntelliJ IDEA as illustrated in the following figure. The size of this file is
about 577 MB.
1-13
Flutter ™ Application Development
5- Our plan is to use IntelliJ to develop Dart ; therefore , no need to select any of the
below choices. Click Next
1-14
Introduction to Dart AFD-200
6- Keep the default start menu folder as illustrated in the below figure. Click Install
1-15
Flutter ™ Application Development
9- In the this step, select I confirm that I read and accept the terms of this User
Agreement, then click Continue.
1-16
Introduction to Dart AFD-200
10- In this step, as illustrated in the below figure , click Don't send
1-17
Flutter ™ Application Development
11- In this step, you may select your IntelliJ IDEA user interface theme. Almost most
developers select Darcula theme because it is more comfortable for eyes; however,
we will select Light theme for printing considerations. Select Light or Darcula , then
click Next Default plugins
1-18
Introduction to Dart AFD-200
14- You will get the following IntelliJ IDEA startup dialog box.
1-19
Flutter ™ Application Development
15- Now, you will install Dart plugins which will make the connection between
IntelliJ IDEA and Dart SDK. Click Configure, then select Plugins as illustrated in the
below figure:
16- You will get the following figure. Move your mouse cursor to the search area as
illustrated in the blow figure, type Dart, and then press Enter key
1-20
Introduction to Dart AFD-200
18 - After completing the Dart plug-in installation step, click Restart IDE .
1-21
Flutter ™ Application Development
19 - Click Restart.
21- To connect IntelliJ IDEA with Dart SDK, as illustrated in the below figure, click
Dart in the left side.
1-22
Introduction to Dart AFD-200
22- Configure the Dart SDK path on your computer. Click the browse button, then
click your Dart SDK path. As illustrated in the below figure, Dart SDK path is :
C:\Program Files\Dart\dart-sdk
To generate a sample code just to test the working of IntelliJ IDEA with Dart, select
Console Application - a command-line application sample , and then click Next
23- As illustrated in the next figure, type the Project name: Lab_1, then click Finish
1-23
Flutter ™ Application Development
24- Remove the check mark at Show tips on startup as illustrated in the below
figure, and click Close
{ )main(List<String> arguments
;)'!})(print('Hello world: ${Test.calculate
}
Now, we will run this sample code just to be sure that IntelliJ IDEA works fine with
Dart configuration. Click Run button or click Run menu → Run
As illustrated in the below figure, you will get the following run code result:
“Hello world: 42 !”, this means IntelliJ IDEA works fine.
1-24
Introduction to Dart AFD-200
3- In the New Project dialog box, as illustrated in the below figure, type the Project
Name: My First Dart App, then click Finish.
1-25
Flutter ™ Application Development
1-26
Introduction to Dart AFD-200
In the previous figure, we have labeled the IntelliJ interface parts as follows :
A : Menu and Tools Bar
B: Navigation Bar
C: Project Console
D : Editor Window
E: Tool Window
F: Status Bar
main() {
1-27
Flutter ™ Application Development
main() is a method and you must write the entire code within the two braces {} of
this main method.
8- Write the following code within the two braces of the main method as follows:
main() {
print('Welcome to Android ATC');
}
The print method is used in Dart to print text or variable value in the Run console
as illustrated in the figure below.
Then, from Run menu, click Run. You will get the following run result:
1-28
Introduction to Dart AFD-200
Using DartPad
DartPad is an open-source tool that lets you work with the Dart language in any
modern web browser. It is a great, no-download-required way to learn Dart syntaxes
and to experiment Dart language features.
The following steps show how you can write a Dart code using DartPad:
1- Go to: https://dartpad.dev
2- Delete the exiting code which are in the left side, then write the following code:
main() {
print('Welcome to Android ATC');
}
3- Click the Run button, then you will get the running program output in the
CONSOLE side as illustrated in the following figure:
1-29
Dart Programming - Syntax AFD-200
Introduction............................................................................................................................ 2-2
main( ) function...................................................................................................................... 2-2
Dart Variables......................................................................................................................... 2-4
Dart Data Types...................................................................................................................... 2-5
Input of Information to Dart Program................................................................................... 2-15
Writing Comments................................................................................................................. 2-17
Dart Conditional Operators.................................................................................................... 2-19
If Statement............................................................................................................................ 2-22
If – Else Statement................................................................................................................ 2-24
If…Else and Else…If... Statement.......................................................................................... 2-25
If Else and Logical Operators................................................................................................ 2-26
For Loops................................................................................................................................ 2-28
While Loops............................................................................................................................ 2-29
Do-while Loops...................................................................................................................... 2-31
Break Statement.................................................................................................................... 2-32
Switch Case Statement......................................................................................................... 2-33
Lab 2: Create a Pizza Order Program.................................................................................... 2-36
2-1
Flutter ™ Application Development
Introduction
This lesson shows you how to use major Dart features including variables,
operators, classes and libraries.
•• Comments
•• Classes
•• Functions
In this lesson, you will learn more about each of the above statements, especially
the role and the use of each of them with examples.
main() function
A function is any close identity which includes a certain code or a collection of
statements grouped together to perform an operation.
Every app must have a top-level main() function, which serves as the entry point to the app.
2-2
Dart Programming - Syntax AFD-200
All your Dart code must be written inside the main() function body.
Example:
main() {
print('Welcome to Android ATC');
print(1+1);
}
3- Run this Dart file (Click Run menu , then select Run).
The result follows:
Example :
Continue using the previous example, and add another function called test()
outside the main() function body as illustrated in the code below:
main() {
print('Welcome to Android ATC');
print(1+1);
}
test(){
print('Hello Flutter Developers');
}
When you run this Dart code, you will get the same previous result without any
2-3
Flutter ™ Application Development
This means that, when you run any Dart code, only the code inside the main( )
function body will run. Also, if you want to run any function outside the main()
function body, you must add a reference to this external function inside the main( )
function as you will see in the next topics.
Dart Variables
A Dart variable is a piece of memory that can contain a data value. Variables are
typically used to store information which your Dart program needs to do its job.
These variables are case sensitive.
To declare a variable, write var directly before the variable. The following example
gives you an idea about how to use a variable called x :
main() {
print('Welcome to Android ATC');
var x=1;
print(x);
}
When you run this Dart program, you will get the following result for x value:
You also can declare the variables outside the main() function body as illustrated in
the following example:
var y=2;
main() {
print('Welcome to Android ATC');
2-4
Dart Programming - Syntax AFD-200
var x=1;
print(x);
print(y);
}
When you run this Dart program, you will get the following result for x and y values:
1) String
String data type is used to store words or sentences. If you want to assign a data type for a
specific variable as string, you cannot assign a number or a symbol for this variable
String values in Dart can be represented using either single or double quotes.
Example:
The following code displays how you must declare a string variable. In this example,
the word String has been written directly before the name variable.
main() {
String Name= 'William';
print(Name);
}
2-5
Flutter ™ Application Development
2) Booleans
A Boolean data type has two possible values; either true or false. Booleans are used
in decision making statements which you can control in the program work flow.
Example:
The following code displays how you must declare a Boolean variable. To declare a
Boolean value, you must write bool directly before the variable.
main() {
bool xyz;
xyz = 12 > 5;
print(xyz);
}
If you changed the formula to xyz=12 < 5; and run the code, the run output will be :
false. This is because xyz variable has been declared as a Boolean variable.
2-6
Dart Programming - Syntax AFD-200
3) Numbers
Dart provides the following built-in types that represent numbers:
The following example shows how to declare integer variables and use them in a
sum formula:
main() {
int x=3;
int y=2;
int z=x+y;
print(z);
}
If you want to use a decimal number, you must use double data type. To declare a
double variable, write double directly before the variable as illustrated in the following
code:
2-7
Flutter ™ Application Development
main() {
double height=1.5;
double width=2.6;
double area=height*width;
print(area);
}
Also, as it illustrated in the following code, you may use "num" to declare an integer
or a double number.
main() {
num x=1;
num y=1.5;
num z=x*y;
print(z);
}
2-8
Dart Programming - Syntax AFD-200
You can say in a simple way, we will use integer for whole numbers and double for
decimal numbers.
4) Lists
A very commonly used collection in programming is an array. Dart represents arrays
in the form of List objects. If you want to store a large number of data items for the
same variable, you need to use the list. A list is used to store a group of values, all of
which have the same data type.
As you see in the following figure, this list contains 10 values starting from list [0]
whose value is 14 until list [9] whose value is 45.
Example:
The following code includes a list called test_list contains 10 different values :
main() {
var test_list = [7,3,100,50,9,30,8,11,6,-4];
print(test_list[2]);
}
2-9
Flutter ™ Application Development
Also, you can write the same previous list code and declare their data type as
integer as follows:
main() {
List<int> test_list = [7,3,100,50,9,30,8,11,6,-4];
print(test_list[2]);
}
Example:
The following code is to print the all the content of the List test_list :
main() {
var test_list = [7,3,100,50,9,30,8,11,6,-4];
print(test_list);
}
2-10
Dart Programming - Syntax AFD-200
Example:
In the following Dart code, you will see how to use the add method to add a new
value to the existing List. The new value will be added at the end of this List.
main() {
var test_list = [7,3,100,50,9,30,8,11,6,-4];
test_list.add(400);
print(test_list);
}
Example:
In the following Dart code, test_list.length method represents the number of the
list length. Here in this example, the list contains 10 numbers from test_list[0]
until test_list[9].
2-11
Flutter ™ Application Development
main() {
var test_list = [7,3,100,50,9,30,8,11,6,-4];
print(test_list.length);
}
Example:
As illustrated in the following Dart code, the forEach method is used to print each
list element.
main() {
var test_list = [7,3,100,50,9,30,8,11,6,-4];
test_list.forEach((x){
print(x);
});
}
5) Maps
DART maps is an object that associates keys to values. In Dart, maps is an interface
designed to manipulate a collection of keys which points to values. Maps can be
declared in two ways, using maps literals and using a map constructor as follows:
To declare a map using map literals, you need to enclose the key-value pairs within
2-12
Dart Programming - Syntax AFD-200
a pair of braces
"{ }".
Example:
main() {
var info = {'UserName':'Kevin@androidatc.
com','Password':'pass123'};
print(info);
}
To declare a Map using a Map constructor, there are two steps. First, declare the
map as follows:
info['UserName'] = '[email protected]';
Example:
main() {
var info = new Map();
info['UserName'] = '[email protected]';
info['Password'] = 'Canada@123';
2-13
Flutter ™ Application Development
info['Country'] = 'Canada';
info['City'] = 'Toronto';
print(info);
}
main() {
2-14
Dart Programming - Syntax AFD-200
Here, at the first line of code, add : import 'dart:io' to import the dart:io library.
This library allows IntelliJ to accept the input of information commands.
import 'dart:io';
main() {
print('=============================');
print('Please enter your full name:');
String Full_Name=stdin.readLineSync();
print('Hello:$Full_Name');
print('=============================');
}
When you run this program, you will get the following message:
Then, enter your full name, then press Enter or Return key, you will get the following result :
2-15
Flutter ™ Application Development
import 'dart:io';
main() {
var sum=num1+num2;
When you run this program, you will get the following message :
Enter 5, then press Enter or Return key. You will get the following message:
2-16
Dart Programming - Syntax AFD-200
Enter 3, then press Enter or Return key, you will get the following result :
Writing Comments
Any line starting with a double forward slash will be considered a comment by the
Dart compiler. This means that this part will not run or appear to the users of this
application because it will remain internal. Comments are used to write notes about
different parts of the Dart program.
Example:
In the previous code, you may add the following line as a comment:
// The following code to input data to Dart program
import 'dart:io';
main() {
2-17
Flutter ™ Application Development
When you run this program, the part which starts with a double forward slash will
not appear to users.
Also, if you want to stop any part of the program temporarily, you can do that by
adding a double forward slash at the beginning of this line of code as illustrated in
the grey highlighted part of the following code:
import 'dart:io';
main() {
Besides, you may configure a block of comments which include more than one line
if it starts with /* and ends with */. These (/* & */) are used to add multiple lines of
comments in the code without adding // at the beginning of each line as illustrated
in the following code:
import 'dart:io';
main() {
2-18
Dart Programming - Syntax AFD-200
*/
}
Operator Description
== Equal to
=! Not Equal to
< Less than
=< Less than or equal to
> Greater than
=> Greater than or equal to
? Return value of two expressions
Return the which is not equal null value of two expres-
??
sions
is Is
!Is Is Not
Example: In the following code, you will test the role of double equal sign "==" which
is used to compare if two values are equal or not. If they are equal, then the run
result will be true; otherwise, the run result will be false.
main() {
int x=3;
2-19
Flutter ™ Application Development
int y=5;
print(x==y);
}
Example:
The following Dart conditional operator "?" will return one expression (exp1 or exp2)
as illustrated in the following figure :
The following code has an example about using "?" Dart conditional operator:
main() {
var Age=20;
var x=Age >18 ? "Allow" : "Deny";
print(x);
}
2-20
Dart Programming - Syntax AFD-200
Because the "Age" value in this example is 20, the condition result is true, so the
run result will be Allow as illustrated in the following figure:
Example:
In the following example, the conditional operator "??" is used to compare two
expressions, and then return the value of the expression which is not equal to a null
value as illustrated in the following code:
main() {
var x=null;
var y=10;
var z=x ?? y ;
print(z);
}
Example:
The following code displays using "is" operator. If the condition operator result is
true, the output will be true; otherwise, the result will be false.
2-21
Flutter ™ Application Development
main() {
int x=5;
print(x is bool);
}
If Statement
The "if" statement is a programming conditional statement that, if proved true,
executes the second part of the statement. Otherwise, if proved false, the program
will skip the execution of the second part and do something else.
Example:
In the following example, the Dart compiler will consider the "if" condition and the
statement highlighted in grey color in this example as one block. if x>5 (true) the
program will print a hello message, and if it is not (false), the program will continue
to perform the next action.
main() {
int x=10;
if(x>5){
print("Hello, I am If statement running now ......");
}
print('The End');
2-22
Dart Programming - Syntax AFD-200
main() {
int x=2;
if(x>5){
print("Hello, I am If statement running now ......");
}
print('The End');
2-23
Flutter ™ Application Development
IF – Else Statement
The if-else statement is the most basic of all the control flow statements. It invokes your
program to execute a specific section of a code only if a particular test proves to be true.
The following figure displays the work of the IF - Else statement:
Example:
This example gives an idea of how if-else statement works in an easy way:
In the Dart program below, when the program starts, the value of the x variable =10.
In the next line, the "if" statement will work using the greater than condition. After
the Dart compiler checks whether this condition is true or not, Dart compiler will
directly run the next line of code. However, if the condition is proved not true, Dart
compiler will continue to run the code lines under the Else statement.
main() {
int x=10;
if(x>30){
print("Hello, I am If statement running now ......");}
else
{
print("Hello, I am Else statement running now ......");}
2-24
Dart Programming - Syntax AFD-200
main() {
var score=85;
if(score>=90){
print('Grade: A');
}
else if (score>=80) {
print('Grade: B');
}
else if (score>=70) {
print('Grade: C');
}
else if (score>=50) {
print('Grade: D');
}
else {
print('Grade: F');
}
}
2-25
Flutter ™ Application Development
This example includes four "if" statements. Dart compiler follows the code line by
line from top to bottom. If any of these "if" statements is true, it will run the action
that belongs to it, and then moves directly to run the code which comes after the
last else statement. However, if any statement proves to be not true, the program
moves to check the next "if" statement.
If you change the score value to 40, the program run result will be as follows:
2-26
Dart Programming - Syntax AFD-200
A B
True True True
True False True
False True True
False False False
The following table displays the use of "&&" (AND) logical operator to guarantee that
the two conditions are true:
A B
True True True
True False False
False True False
False False False
Example:
The following example includes two conditions. It is enough to prove one of the
conditions to consider the "if" condition is true because you used the | | operator.
main() {
var Age = 16;
var DOB = 1998;
2-27
Flutter ™ Application Development
If you replaced the | | operator with && operator as illustrated in the following code:
main() {
var Age = 16;
var DOB = 1998;
You will get the following run result because the "if" condition will be considered
true only if the two conditions are true. In this case, if the condition is false, else
statement will work as shown below:
For Loops
A for statement provides a compact way to iterate over a range of values.
Programmers often refer to it as the "for-loop" because it repeatedly loops until a
particular condition is satisfied.
2-28
Dart Programming - Syntax AFD-200
main() {
// for loop
for (var i = 0; i < 5; i++) {
print("i= $i");
}
}
When the program starts, the i variable has a value = 0. However, when the Dart
compiler runs the code below within the "for" loop braces and finishes its loop, the
"i" variable takes the second value which is 1, and so on until it takes the last value
which is 4 here. When the "i" variable takes its final value, the Dart compiler will
resume its work outside the "for" loop braces.
When you run the Dart program, you will get the following result:
While Loops
A while-statement depends on a Boolean expression and its counter. If the
expression proves to be true, the While statement executes the statement(s) in the
While block. The while statement continues testing the expression and executing
its loop until the expression is proved false.
2-29
Flutter ™ Application Development
main() {
var x=1;
while (x<=5)
{
print("x= $x");
x++;
// this is the counter for the loop means x=x+1 i.e. increment x by
1
//each time
}
}
The following steps illustrate the flow of execution of the previous code:
1- The initial value of integer variable named x as 1.
2- The compiler checks the condition (x < =5) which proves to be true, so it moves
into the code block of the While statement and prints "x=1".
3- The counter variable is incremented to value 1 and the compiler loops to the top.
4- The compiler checks again the While loop condition (x < =5) which proves to be
true, so the compiler prints "x=2" and increments the counter variable to value 2.
5- The program will continue working until it reaches x=6. After that the compiler
checks again the While loop condition (x < =5) and proves to be false, the compiler
will skip the code block and move forward to execute the code of the statements
that follows the While statement.
When you run the Dart program, you will get the following result:
2-30
Dart Programming - Syntax AFD-200
Do-while Loops
Contrary to the while-loop, the Do-while loop starts evaluating its expressions
from the bottom and not from the top. Thus, the statements within the do block are
executed at least once. Do-while loops are exit controlled loops, i.e. the compiler
will first execute the code block associated with the Do-while loop, and then check
the associated Boolean expression. If the Boolean expression proves to be true, the
compiler will loop and execute the Do-while code block again, or else, the compiler
will skip the Do-while code block and continue to execute the statements that
follow the Do-while loop.
The following figure displays the work flow of the Do-while loop:
2-31
Flutter ™ Application Development
main() {
var x=1;
do {
print('x= $x');
x++; }
while (x<=5);
}
When you run the Dart program, you will get the following result:
Break Statement
The break statement allows you to exit a loop at any point, and overpasses its
normal termination expression. When the break statement is encountered inside
a loop, the loop is immediately terminated, and resumes its work starting from the
statement that follows the loop. The break statement can be used in any type of
loop such as the While, Do-while, or For-loops.
The following code displays the same Do-while loops example code used
previously. In this example, when the count of variable x becomes equal to 3, the
break statement will terminate the While-loops. Then, the program control will
resume its work starting with the statement following the While loops:
2-32
Dart Programming - Syntax AFD-200
main() {
var x=1;
do {
print('x= $x');
x++;
if(x==3) break; }
while (x<=5);
}
When you run the Dart program, you will get the following result:
The following code example, declares an int named "day" whose value represents
a day. The code displays the name of the day, based on the value of day, using the
switch statement. When day=2, case 2 will work, and the today variable will be
Monday, then the break statement will move to outside the switch block of code. In
case no statements are running, the default statement will be selected.
main() {
int day = 2;
String today = null;
2-33
Flutter ™ Application Development
switch (day) {
case 1: today = 'Sunday';
break;
case 2: today = 'Monday';
break;
case 3: today = 'Tuesday';
break;
case 4: today = 'Wednesday';
break;
case 5: today = 'Thursday';
break;
case 6: today = 'Friday';
break;
case 7: today = 'Saturday';
break;
default: today = 'Invalid Day'; }
print("Today is : $today");
}
When you run the Dart program, you will get the following result:
When you change "day" variable to 3 , and run the Dart program, you will get the
following result:
2-34
Dart Programming - Syntax AFD-200
When you change "day" variable to 9 , the default statement will work , and the
run result will be as follows:
2-35
Flutter ™ Application Development
Here, you will create a simple pizza order calculator so that when you run this
program, the program will ask the user to enter the pizza size and the quantity of
pizza the user wants. Then, the output of the run result will be the total of the user
payment.
4- Right click the project name and select: New → Dart File
2-36
Dart Programming - Syntax AFD-200
5- Type the Dart file name "main" as illustrated in the following figure, then press Enter:
6- At the beginning of the code (first line), type the following code to enable the
input library:
import 'dart:io';
import 'dart:io';
main() {
print('========================================================');
print('Pizza Price "Small: 5 USD , Medium : 7 USD ,Large:10
USD"');
print('Please enter your pizza size (small, medium , or large):');
if(pizza_size=="small"){
price=5;
var total=price*Qty;
print("Your Total Payment is : $total");
}
else if(pizza_size=="medium") {
price=7;
var total=price*Qty;
print("Your Total Payment is : $total");
}
else if(pizza_size=="large") {
price=10;
var total=price*Qty;
2-37
Flutter ™ Application Development
else {(pizza_size==null);
print('Invalid Pizza Size Input. Please Run This Program Again
!!');
}
}
8- Right click main.dart file name, then select Run 'main.dart' as illustrated in the
following figure:
10- Type in the Run console area : small and press Enter key.
2-38
Dart Programming - Syntax AFD-200
12- Type 3 and press Enter key. You will get the following result:
13- Run this program again using medium or large sizes and test your results.
14- If you run this program again using invalid pizza size, such as "big", the result
will be as follows:
Note: You may create the same program using Switch Case statement.
2-39
Dart Functions & OOP AFD-200
Functions................................................................................................................................ 3-2
Function Structure............................................................................................................ 3-2
Creating a Function........................................................................................................... 3-2
Function Return Data Types............................................................................................. 3-4
Void Function.................................................................................................................... 3-7
Function Returning Expression........................................................................................ 3-9
Functions and Variable Scope.......................................................................................... 3-10
Object-Oriented Programming (OOP)................................................................................... 3-12
Object................................................................................................................................. 3-12
Class.................................................................................................................................. 3-13
Creating a Class................................................................................................................ 3-13
Adding Methods to Classes.............................................................................................. 3-18
Providing Constructors for Your Classes......................................................................... 3-19
Class — Getters and Setters............................................................................................. 3-25
Class Inheritance............................................................................................................... 3-27
Abstract Class................................................................................................................... 3-28
Dart Project Structure and Dart Libraries............................................................................. 3-33
Lab 3: Create a Small Overtime Payment Program............................................................. 3-40
3-1
Flutter ™ Application Development
Functions
A function in Dart or in any programming language has a specific name and has
a set of programming statements. The function can be called at any location of
the program to run the statements it has and returns a result, or performs some
operations. This process saves time and effort in writing all the function statements
one time, then at a certain location of the code call this function by its name to
perform a specific procedure or return a value. Also, functions help in organizing
the program to structured parts which help in program maintenance and any future
modifications.
Each function has a unique name which is used to call it inside the Dart program
several times without the need to duplicate statements in multiple source code files.
Most programming languages come with a prewritten set of functions that are kept
in a library.
Function Structure
The following image displays the main components of the main function:
Creating a Function
If you have a number of code statements that need to be used more than once
within your program, you can gather them inside a function which has a specific
name and then call this function within the program as many times as needed.
Example: In the following example, if you run the following code, the compiler will run
the code which is in the main function only.
3-2
Dart Functions & OOP AFD-200
main() {
PrintSomething(){
print("Hello Functions !!");
print("Welcome to Canada");
}
Since we don’t have any code inside the main() function, the run output result will
be empty as illustrated in the following figure:
If you call the PrintSomething() function inside the main()as illustrated in the
following figure:
3-3
Flutter ™ Application Development
main() {
PrintSomething();
}
PrintSomething(){
print("Hello Functions !!");
print("Welcome to Canada");
}
main() {
CourseName();
String CourseName(){
return "Flutter Application Development";
}
3-4
Dart Functions & OOP AFD-200
As you see in the next code, we must add a print() function to display the
CourseName()function return:
main() {
print(CourseName());
}
String CourseName(){
return "Flutter Application Development";
}
3-5
Flutter ™ Application Development
Example: In the following example, the SumCalculator function will return an integer
value of the sum of two numbers to the main() function.
main() {
int SumCalculator(x,y){
var z=x+y;
return z;
}
The same previous code can be written in the following way and you will get the
same run output:
main() {
int SumCalculator(x,y){
var z=x+y;
return z;
}
3-6
Dart Functions & OOP AFD-200
Note: In the previous example, it is important to add the return command at the end
of the SumCalculator function. This will return the result of the addition operation,
variable z, to the location from where the function was called.
Example:
In the following code, the age() function will return a Boolean value (true or false)
depending on the value of age “x” :
main() {
print(age(20));
}
bool age(x){
if(x>=18){
return true;
}
else{
return false;}
}
Void Function
A void function returns values by modifying one or more parameters rather than
3-7
Flutter ™ Application Development
main() {
MyFunction();
}
void MyFunction(){
var FirstName='George';
if(FirstName.startsWith('G')){
print("The first name starts with G");
}
else {
print("The first name does not start with G");
}
All functions by default are void functions ; therefore, in the previous example, if you
remove the "void" before the function name, you will get the same result.
3-8
Dart Functions & OOP AFD-200
main() {
sum(x,y){
var z=x+y;
return z;
}
multiply(x,y){
var w=x*y;
return w;
}
However, if you use the => operator to return the expression "x+y" or "x*y" , you will get the
same result but with less number of code lines, as illustrated in the following example:
main() {
var x=3;
var y=5;
3-9
Flutter ™ Application Development
int sum()=>x+y;
int multiply()=>x*y;
print('The Sum Result is : ${sum()}');
print('The Multiply Result is : ${multiply()}');
}
var name='Microsoft';
main() {
CompanyName(name);
}
CompanyName(name){
print('My Company Name is : $name');
}
3-10
Dart Functions & OOP AFD-200
Now, as illustrated in the next code, we will configure the name variable inside the
CompanyName(name) function . This means that name variable is considered as a
local variable for CompanyName(name) function.
var name='Microsoft';
main() {
CompanyName(name);
}
CompanyName(name){
var name='Google';
print('My Company Name is : $name');
}
Since the local variable will be dominant over any other configurations that may
come from outside this function, the run result of this code will be follows:
3-11
Flutter ™ Application Development
Also, the same thing applies in the following code. The local variable will take effect
over the global variable:
var name='Microsoft';
main() {
CompanyName('Android ATC');
}
CompanyName(name){
print('My Company Name is : $name');
}
Object
Objects are the key to understanding object-oriented technology. Look around you
right now and you will find many examples of real-world objects: your car, your desk,
your computer, your house etc.
3-12
Dart Functions & OOP AFD-200
Real-world objects share two characteristics: state and behavior. Computers have
a state (type, color, speed, capacity) and behavior (processing, playing media,
browsing). A car also has a state (current gear, current pedal cadence, and current
speed) and behavior (changing gear, changing pedal cadence, applying brakes).
Identifying the state and behavior for real-world objects is a great way to begin
thinking in terms of object-oriented programming.
Class
A class is a blueprint or prototype (template) from which objects are created. This
section defines a class that models the state and behavior of a real-world object. It
intentionally focuses on the basics, showing how even a simple class can clearly
model state and behavior. Classes are characterized by properties and functions.
For example, if the class is a car, it may have the following properties:
•• Price
•• Type
•• Maximum speed
•• Number of seats
Creating a Class
Use the class keyword to declare a class in Dart. A class definition starts with the
keyword class followed by the class name; and the class body enclosed by a pair of
curly braces.
A class code includes the class name and a group of properties or attributes which
will construct the class.
Example:
The following example shows how you can create a class called car step by step:
Step 1: Declare an empty class called “car”, as illustrated in the following code:
3-13
Flutter ™ Application Development
class car {
main() {
Step 2: The car class has been created. Now, you may add some properties to this
car class as illustrated in the following code:
class car {
String type;
String color;
int MaxSpeed;
int NumOfSeats;
}
main() {
Step 3: To create an instance of the class or object, use the new keyword followed
by the class name. Here, you can create an object depending on the “car” class (blue
print) which you have created in step 1, using the following code. toyota is the
name of the object which has all car class properties or attributes values.
class car {
String type;
String color;
int MaxSpeed;
int NumOfSeats;
}
main() {
var toyota=new car();
3-14
Dart Functions & OOP AFD-200
As you see in the following image, the toyota object can use all the car class
properties:
The following code displays the object toyota with some properties values:
class car {
String type;
String color;
int MaxSpeed;
int NumOfSeats;
}
main() {
var toyota=new car();
toyota.MaxSpeed=200;
toyota.color="red";
toyota.NumOfSeats=5;
toyota.type="Camry";
}
3-15
Flutter ™ Application Development
For example, if you add the following command to the main() function, you can
print a specific attribute or property value (type) of toyota object :
Also, you may assign a default value for these class properties such as NumOfSeats
as illustrated in the following grey highlighted part of the following code:
class car {
String type;
String color;
int MaxSpeed;
int NumOfSeats = 4;
}
main() {
var toyota=new car();
toyota.MaxSpeed=200;
toyota.color="red";
toyota.type="Camry";
3-16
Dart Functions & OOP AFD-200
However, if you configure a specific value for NumOfSeats to the object “toyota”, it
will override any other values as illustrated in the following code:
class car {
String type;
String color;
int MaxSpeed;
int NumOfSeats = 4;
}
main() {
var toyota=new car();
toyota.MaxSpeed=200;
toyota.color="red";
toyota.type="Camry";
toyota.NumOfSeats=7;
3-17
Flutter ™ Application Development
class car {
String type;
String color;
int MaxSpeed;
int NumOfSeats = 4;
void CarSpeed(){
print(“Car Speed is : $MaxSpeed”);
}
}
As illustrated in the following figure, you can use this CarSpeed()method with the
toyota object:
3-18
Dart Functions & OOP AFD-200
class car {
String type;
String color;
int MaxSpeed;
int NumOfSeats = 4;
void CarSpeed(){
print("Car Speed is : $MaxSpeed");
}
}
main() {
var toyota=new car();
toyota.MaxSpeed=200;
toyota.color="red";
toyota.type="Camry";
toyota.NumOfSeats=7;
3-19
Flutter ™ Application Development
Example:
In the previous example, you initialized toyota object from the car class using the
following command:
Now, you will construct the same object using a constructor which has the same
class name.
First, I will create the car class again as illustrated in the following code:
class car {
String type;
String color;
int MaxSpeed;
int NumOfSeats;
main() {
Now, add the following highlighted grey color code which represents the car
constructor which has the same class name.
this : The this keyword refers to the current instance of the class.
class car {
String type;
String color;
int MaxSpeed;
int NumOfSeats;
3-20
Dart Functions & OOP AFD-200
main() {
Now, you can construct or initiate an object using the car constructor as illustrated
in the grey highlighted color part of the following code:
class car {
String type;
String color;
int MaxSpeed;
int NumOfSeats;
main() {
3-21
Flutter ™ Application Development
Also, in the previous example, you can create the previous car constructor code in another
way using the least number of lines of code by replacing the following part of a code:
class car {
String type;
String color;
int MaxSpeed;
int NumOfSeats;
main() {
3-22
Dart Functions & OOP AFD-200
Example:
Also, you can initialize an object using a constructor name. The following code
creates the car class, and then using the constructor car.initialize(), you can
assign the attributes values as follows:
class car {
String type;
String color;
int MaxSpeed;
int NumOfSeats;
car.initialize(){
type="Mini Van";
color="Green";
MaxSpeed=230;
NumOfSeats=2;
}
}
main() {
3-23
Flutter ™ Application Development
Then, as you see in the following figure, you can use the constructor name in
creating the toyota object.
class car {
String type;
String color;
int MaxSpeed;
int NumOfSeats;
car.initialize(){
type="Mini Van";
color="Green";
MaxSpeed=230;
NumOfSeats=2;
}
}
main() {
3-24
Dart Functions & OOP AFD-200
Example:
In the following example, we will use set keyword to set a string value for the type
class attribute , and get keyword to return this class attribute value.
class car {
String type;
String color;
int MaxSpeed;
int NumOfSeats;
main() {
3-25
Flutter ™ Application Development
Now, in the following code, we will use setType to set a value and getType to return
or use this value.
class car {
String type;
String color;
int MaxSpeed;
int NumOfSeats;
main() {
var toyota= new car();
toyota.setType="Bus";
print(toyota.getType);
}
3-26
Dart Functions & OOP AFD-200
Class Inheritance
The idea of inheritance is simple but powerful. When you want to create a new class
and there is already a class that includes some of the codes that you need, you can
derive your new class from the existing class (called parent or super class). While
doing this, you can reuse the properties and methods of the existing class without
having to write them again.
Example:
Assume that you have a class called Student, as illustrated in the following code:
class Student {
String Name;
String Address;
int TelNumber;
String Email; }
main() {
}
If you want to create a new class called Teacher, with the same properties of the
previous class Student, which is the primary class (parent or super class), you can
add the following line to the previous code snippet.
Now, Teacher class has all the properties or attributes of Student class.
You may use this Teacher class to create a new object “trainer” as illustrated in the
following code:
class Student {
String Name;
String Address;
int TelNumber;
String Email;
3-27
Flutter ™ Application Development
main() {
var trainer=new Teacher();
trainer.Email="[email protected]";
trainer.TelNumber=123456789;
print("Email Address : ${trainer.Email}");
print("Telephone Number: ${trainer.TelNumber}");
}
Abstract Class
A class is called abstract when at least one of its methods or functions does not
have an implementation (function body). It is the responsibility of the derived / child
class to provide the implementation of the abstract members of the parent class.
An abstract class needs to be qualified with the abstract keyword. An abstract class
cannot be instantiated, and its only purpose is to be inherited.
Example:
In the following example, Student is a normal class. If you added the contactInfo
method to this class without a method body , you will get an error as illustrated in
the following code:
3-28
Dart Functions & OOP AFD-200
class Student {
contactInfo();
}
main(){
But if you configure Student class as abstract class, as illustrated in the following
code, you can add the contactInfo (abstract method) without method body
(implementation).
main(){
Also, you can’t create an object directly using this abstract class. If you try, you will
get an error (red underline) as illustrated in the following screenshot:
3-29
Flutter ™ Application Development
Instead of that , you should create a child class that inherits these abstract class
(Student) properties and abstract methods, then use this child class in creating new
objects.
In the following code, ITStudent is a child class, and will inherit all the Student
(parent class) properties and methods. When you type the following code , you
will see a red underline below ITStudent because the abstract class ITStudent
includes an empty abstract method called contactInfo.
}
class ITStudent extends Student{
}
main(){
Now, you must add the abstract method: contactInfo to the child class body.
When you try to do that, you will get the following menu as illustrated in the
following screenshot:
When you add the contactInfo method, the error will be removed and you will get
the following code:
3-30
Dart Functions & OOP AFD-200
}
class ITStudent extends Student{
@override
contactInfo() {
// TODO: implement contactInfo
return null;
}
}
main(){
Now, add some properties (method body) to the contactInfo() method and
remove “return null;" as illustrated in the following code:
You can create the SoftwareStudent object from the ITStudent class as
illustrated in the following code:
}
class ITStudent extends Student{
@override
contactInfo() {
// TODO: implement contactInfo
print("Dart fundamentals");
}
3-31
Flutter ™ Application Development
main(){
var SoftwareStudent= new ITStudent();
SoftwareStudent.contactInfo();
}
Although this abstract class has abstract methods, it can include normal methods
also. For example, you can add CourseInfo method with a method body to your
abstract class: Student as illustrated in the following code :
}
class ITStudent extends Student{
@override
contactInfo() {
// TODO: implement contactInfo
print("Dart fundamentals");
}
}
main(){
var SoftwareStudent= new ITStudent();
SoftwareStudent.contactInfo();
SoftwareStudent.CourseInfo();
}
3-32
Dart Functions & OOP AFD-200
When you click Finish, you will get the following window:
3-33
Flutter ™ Application Development
Now, Lesson3 Dart project has been created, and it can include the Dart files which
you want.
For example, to create a main.dart file, right click the Lesson3 project name, then
select: New, then select Dart File. Then, type the file name: main as illustrated in the
following figure and press Enter key.
3-34
Dart Functions & OOP AFD-200
Dart Libraries
The Dart SDK has the libraries and command-line tools that you need to develop
Dart web, command-line, and mobile apps.
You can use the Dart libraries which are already added to your IDE since installing
the Dart SDK, or you can create your own libraries which you may use frequently in
developing your Dart projects. It is recommended to consider these libraries similar
to Microsoft Word templates which you may use for creating different types of
documents such as resumes, invoices or reports.
The Dart SDK includes a libraries directory for the Dart libraries. Also, you may use the
External Libraries, installed with the Dart SDK directory, which includes the libraries
created by Google developers. This directory is illustrated in the following figure:
Example:
3-35
Flutter ™ Application Development
In your main.dart file, write the following command at the top of your dart file to
import math.dart library as illustrated in the following code.
"as math" : means you can use math as reference to use this library. It is similar
to the object name which will represent this library in writing the code. You can use
any word.
Then, in the main function you can use all the methods which are imported to your
Dart project when you start with math, as illustrated in the following figure:
In this example, we will use the maximum function. This function or method will find
the maximum number of two numbers as illustrated in the following code:
3-36
Dart Functions & OOP AFD-200
print(math.max(a, b));
main(){
print(math.max(5, 30));
}
Using this library, saves time and effort in creating a function that can do the same
calculation.
Example:
In this example, continue using the same previous main.dart file and create your
own library. Then, you may use this library with your Dart files.
1- Right click Lesson3 directory → New → Dart File
2- Type the file name : MyLibraries as illustrated in the following figure. Then press
the Enter key:
3-37
Flutter ™ Application Development
5- When you use this library with print method, you will get the following figure:
Note that all the methods inside this library will be ready for use. In this example,
you have created one method.
main(){
print(math.max(5, 30));
print(mylib.SumNumbers(10, 50));
3-38
Dart Functions & OOP AFD-200
main(){
print(math.max(5, 30));
print(mylib.SumNumbers(10, 50));
print(mylib.MultiplyNumbers(2, 4));
3-39
Flutter ™ Application Development
In this lab, you will create a library file called myLib.dart ,which includes a class,
create a main.dart file and then import this library file into the main Dart file.
The following are the lab steps:
1- Open IntelliJ IDEA, then click File → New → Project
2- Select Dart for the project type, then click Next
3- Type Lab3 for the Project Name, then click Finish.
4- Right click Lab3 directory, then select New → Dart File
5- Enter the file name myLib , as illustrated in the following figure, then press the Enter key.
class employee{
String jobTitle;
String location;
double salary;
double Overtimehr; //Number of Overtime hours
3-40
Dart Functions & OOP AFD-200
main(){
if(William.salary>=4000){
extraPayPerhr=10;
}
else{
extraPayPerhr=20;
}
double Total_Salary= William.salary+(William.
Overtimehr*extraPayPerhr);
3-41
Introduction to Flutter AFD-200
4-1
Flutter ™ Application Development
Understanding Flutter
Flutter is Google’s SDK for crafting beautiful, fast user experiences for apps from a
single codebase. It is used for building high-performance, high-fidelity apps for iOS,
Android, and web from a single codebase.
iOS and Android developers have many years in using Objective-C, Swift (Xcode) ,
Java or Kotlin to create iOS or Android apps, and then publish them to Google Play
or Apple stores. Also, because customers prefers to work with one company to
create the same mobile app for Google Play and Apple stores, IT companies have
to hire one or more developers iOS apps and others for Android apps. In addition,
mobile app developers need to learn Java or Kotlin for Android development and
Objective C or Swift for iOS development to increase their chances of getting better
jobs or to provide a complete mobile development solution to their customers.
Now, with Flutter, you will create a single code base only to create one mobile app
valid to work with Android or iOS devices. Also, you can publish it to Google Play or
Apple store. Therefore, Flutter is an amazing language, because it saves time and
effort to create beautiful mobile apps.
Flutter works with existing codes and is used by developers and organizations around
the world. It is a free and open source. Flutter will help you create beautiful, fast
apps, with a productive, extensible and open development model.
Flutter has the following features:
1- Beautiful UI (User Experiences):
Flutter enables designers to deliver their full creative vision without being forced
to water it down due to limitations of the underlying framework. Flutter’s layered
architecture gives you control over every pixel on the screen. It has powerful
compositing capabilities which let you overlay and animate graphics, video, text and
controls without limitations. Flutter includes a full set of widgets (text box, check
box, radio buttons , and others) that deliver pixel-perfect experiences on both iOS and
Android.
2- Fast Results
When you run Flutter apps, they will run fast for the following reasons:
•• Flutter uses an open source 2D graphics library called Skia , which has been built
to support glitch-free, jank-free graphics at the native speed of your device.
4-2
Introduction to Flutter AFD-200
•• Flutter code is powered by the world-class Dart platform, which enables compilation
to 32-bit and 64-bit ARM machine code for iOS and Android, as well as JavaScript
for web and Intel x64 for desktop devices.
3- Productive Development
Flutter offers stateful hot reload, allowing you to make changes to your code and
see the results instantly without restarting your app or losing its state.
4-3
Flutter ™ Application Development
Flutter Framework
The Flutter framework is organized into a series of layers. Each layer is built upon
the previous layer as illustrated in the following figure:
The upper layers of the framework are used more frequently than the lower layers.
The goal of this design is to help you do more with less code. For example, the
Material layer is built by composing basic widgets (checkbox, text box, ...etc) from
the widgets layer, and the widgets layer itself is built by orchestrating lower-level
objects from the rendering layer.
The layers offer many options for building apps. Choose a customized approach to
unlock the full expressive power of the framework, or use building blocks from the
widgets layer, or mix and match. You can compose the ready-made widgets Flutter
provides, or create your own custom widgets using the same tools and techniques
that the Flutter team uses to build the framework.
Nothing is hidden from you. You collect the productivity benefits of a high-level,
unified widget concept, without sacrificing the ability to dive as deeply as you wish
into the lower layers.
4-4
Introduction to Flutter AFD-200
Android Studio
You can use many IDEs for Flutter development, including Android Studio, IntelliJ,
and Visual Studio Code. In this course, we will use Android Studio IDE for Flutter app
development.
3- In the next step, and as illustrated in the following figure, select I reviewed
and accept the Oracle Technology Network License Agreement for Oracle
Java SE, then click Download Jdk button.
4-5
Flutter ™ Application Development
4- After finishing the download process, click the following download button on the
bar above your task bar to start the installation process:
4-6
Introduction to Flutter AFD-200
10 - Then, select I reviewed and accept the Oracle Technology Network License
Agreement for Oracle Java SE then click Download jre-8u251-windows-x64.exe
11- You will be asked to create Oracle account. Click : Create Account under Don't
have an Oracle Account?
Enter your personal information, then click Create Account button.
You will be asked to verify your email. Check your email inbox, and then verify the
Oracle email by clicking Verify email address button. Then, you will get the following
message in your web browser :
"Success. Your account is ready to use.". Click the Continue button.
12- Now, go back to the Oracle login dialog box. Enter your email and password for the
account which you have created, then click Sign in. The download process will start.
13- After finishing the download process, click the following download button on the bar
above your task bar to start the installation process:
4-7
Flutter ™ Application Development
15- After finishing the installation process, you will get the following message : You
have successfully installed Java. Click Close.
16- To verify that you have successfully installed JDK on your Microsoft Windows
computer, use the following command : java –version, and then you will get the Java
version which you have installed on your computer as illustrated in the following figure:
4-8
Introduction to Flutter AFD-200
5- The Android Studio installation wizard will start as illustrated in the following
figure. Click Next.
6- In this step and as illustrated in the figure below, keep the default configuration,
and click Next.
4-9
Flutter ™ Application Development
7- Keep the default installation location as illustrated in the figure below, then click Next.
8- Click Install, then you will get the following figure, and after the installation
complete, click Next
4-10
Introduction to Flutter AFD-200
4-11
Flutter ™ Application Development
12 - In the following step, select Standard, and then click Next as illustrated in the
following figure:
13- In this step, you have two themes for Android Studio user interface. Usually,
professional developers select Darcula theme; however, due to issues related to
printing this book, we prefer a white background. I will select Light, click Next, then
click Finish.
4-12
Introduction to Flutter AFD-200
Now, Android Studio will start installing the Android SDK tools as illustrated in the
following figure:
13- After the installation process is completed, click Finish, then you will get the
following dialog box:
4-13
Flutter ™ Application Development
Flutter SDK
The Flutter SDK has the libraries, command tools, code completion, syntax
highlighting, widget editing assists, run & debug support, and all the tools you need
to develop Flutter apps.
•• Git Tool
•• Flutter SDK
•• Android Studio
•• Android Studio Emulators (Android & iOS emulators or phones) to test your
Flutter apps.
In the previous topic, you already installed Android Studio IDE. In the next topics of
this lessons, you will install and configure the other software which will help you to
create and test your Flutter apps.
To install and run Flutter, your development environment must meet the following
minimum requirements:
4-14
Introduction to Flutter AFD-200
4-15
Flutter ™ Application Development
6- Click Install
7- Click Accept for any warring message, then you will get the following dialog box.
Click Yes.
Now, before creating any new Flutter project, you must check your installation, and
if your Android Studio IDE is ready to create a Flutter project or if there are other
steps or prerequisites that must be done. Flutter Doctor command checks your
4-16
Introduction to Flutter AFD-200
environment and displays a report of the status of your Flutter and Android Studio
installation as you will see explained in the next step.
10- You are now ready to run Flutter commands (Flutter doctor) in the Flutter Console.
Go to : C:\src\flutter , then open : flutter_console.bat, you will get the following console:
If you are using Microsoft Windows operating system, and you wish to run Flutter
commands in the regular Windows command prompt console, take the following
steps to add Flutter to the PATH environment variable:
I- Go to Control Panel , then click System
II- Open Advanced System Settings
III- Click Environment Variables, and under User variables, check if there is an entry
called Path. If the entry exists, click Edit, and append the full path to C:\src\flutter\
bin using ; (semicolon) as a separator from existing values. If the Path doesn’t exist,
create a new user variable named Path with the full path to C:\src\flutter\bin, then
click OK as illustrated in the following figures for Windows 10.
4-17
Flutter ™ Application Development
Note that you have to close and reopen any existing console windows for these
changes to take effect.
11- Now, open the command prompt Run → cmd , then press Enter.
12 - Type the following command : flutter doctor , then press Enter.
This command checks your environment and displays a report of the status of your
Flutter installation. The output for my computer was as follows:
13 - As you see in the flutter doctor command result, to complete the Android Studio
installation, you must accept some Android licenses. To do that, type the following
command, and then press Enter :
4-18
Introduction to Flutter AFD-200
You will get many dialog boxes asking you to accept the Android and Google license
parts as follows:
Accept? (y/N):
Type Y, then press Enter key many times to accept all the Android SDK license parts.
Then, at the end you will get the following figure:
Now, type the following command in the command prompt again. Then press Enter:
flutter doctor
4-19
Flutter ™ Application Development
As you see in the previous Flutter doctor command run result, you still need to
install or add a virtual device (virtual phone) or Android emulator to your Android
Studio IDE. The virtual devices (mobile , tablets , smart watch , TV or other) allow
you to test your application without having to have the physical devices on hand.
To add this device, you should open Android Studio, create a Flutter application, and
then use AVD Manager tool in Android Studio to add an Android emulator (virtual
phone).
Remember, that to create a Flutter app, you need to download and install the
following:
4-20
Introduction to Flutter AFD-200
4- In the next step , and as illustrated in the following figure, you will enter the Flutter
project name, Flutter SDK path, and determine the project save location.
5- In the next step, Android Studio asks for an organization name in reverse domain
order such as com.androidatc along with the name of the app used as the package
name for Android, and the Bundle ID for iOS when the app is released (published). If
you think that you might ever release this app to the Google Play or Apple store, it is
better to specify them now. They cannot be changed once the app is released. Your
organization name should be unique.
4-21
Flutter ™ Application Development
Type only: androidatc.com, and then the package name will be : com.androidatc.
lesson4app1 as illustrated in the following figure. Then click Finish.
Then, you will get the following figure which includes the default main.dart file. This
file includes Dart code written by Flutter team.
4-22
Introduction to Flutter AFD-200
The following figure displays the name of each part of the Android Studio interface:
1 → The navigation bar helps you navigate through your project and open
files for editing. It provides a more compact view of the structure visible in
the Project console.
2 → The toolbar lets you carry out a wide range of actions, including running your
app and launching Android tools.
3 → The editor window is where you add a new or modify an existing code to flutter app files.
4 → The tool window bar runs around the outside of the IDE window and contains
the buttons that allow you to expand or collapse individual tool windows.
5 → The tool windows give you access to specific tasks like project management,
search, version control, and more. You can expand and collapse them.
The following figure displays some parts of Android Studio tool bar:
4-23
Flutter ™ Application Development
Before adding a virtual device to your Android Studio, be sure that your computer BIOS
is configured to enable a virtualization feature. This allows virtual devices such as
phone emulators to run on your computer. To know if this feature is enabled on your
computer BIOS, open your Android Studio, then click Tools menu, select SDK Manager,
and click SDK Tools tab in the right side as illustrated in the following figure:
Here, check if the last choice which is Intel x86 Emulator Accelerator (HAXM
installer) is installed. This means the virtual feature is already enabled on your
computer BIOS.
If this option is not installed, try to install it by checking its checkbox. Then click
Apply button. If you get an error message such as : Unable to install Intel HAXM,
HAXM device is not found, you must check your computer BIOS by restarting your
computer, and during the startup process continue pressing F2 , F1 , or Esc key
depending on your computer motherboard settings until you start your computer
BIOS system. You must enable your computer BIOS virtualization feature as
4-24
Introduction to Flutter AFD-200
illustrated in the next two images. Select the Security tab. Then select Virtualization
using your keyboard keys.
Note: The location of virtualization feature in the BIOS system may vary depending
on the hardware vendor type.
Press Enter, to edit the virtualization configuration. Be sure that this feature is enabled
as illustrated in the figure below. If not, press the tab key to change its status from
disabled to enabled.
4-25
Flutter ™ Application Development
1- Click the AVD Manger button on the Android Studio tool bar, or click:
Tools → AVD Manger, then you will get the following dialog box:
2- Click Create Virtual Device button, then you will get the following dialog box:
4-26
Introduction to Flutter AFD-200
5- Click Download. The download process will start as illustrated in the following figure.
This file size is about 723 MB. Click Finish when you complete the download process.
4-27
Flutter ™ Application Development
6- Click Next .
If you get a message as illustrated in the below figure in the Recommendation
saying : HAXM device is not found , just click Finish. In the next topic, you will find
some techniques that suggest ways to solve this issue.
4-28
Introduction to Flutter AFD-200
Microsoft and may cause a conflict or damage with any other operation system files.
So, if your computer BOIS is already enabled to use virtualization feature, try to use the
following techniques to solve this issue:
1- Press Windows key + R, then type gpedit.msc
2- Click User Configuration → Administrative Templates → System → Driver Installation
3- In the right side of this console, double click the Code signing for device drivers
4- Select Enabled , and select Ignore under the Option configuration in the right side, and
then click OK. Then, close this console. “Ignore” option directs the operating system to
proceed with the driver files installation even if it includes unsigned files from Microsoft.
5-Safe Mode startup. In this step, you must startup your computer in safe mode. If
your computer O.S is Windows 7 or 8, follow the following steps:
•• Restart your computer and press F8 key in 1 second interval during startup process.
•• Select Disable Driver signature Enforcement, then press Enter. Your computer
will startup normally but without any restriction on installing unsigned files from
Microsoft.
6-If your computer O.S is Windows 10, you can get the Safe Mode options by
observing the following steps:
8- Open Android Studio IDE . Click Tools → SDK Manager, and then click SDK
Tools tab. Uninstall Intel HAXM software by un-checking the : Intel x86 Emulator
Accelerator (HAXM installer), click Apply, select it again, then click Apply to install it
again. After completing the new installation process, click OK.
9- If you have a problem with installing the Intel x86 Emulator Accelerator (HAXM installer), go to
https://github.com/intel/haxm, and download HAXM for Windows. Then repeat step 7 again.
10- Close Android Studio IDE , restart your computer, open your Android Studio, and
test your emulator by clicking the Run menu. Then select Run. It will work fine.
4-29
Flutter ™ Application Development
Finally, from your Android Studio, click Tools → AVD Manager as illustrated in the
following figure. Then click the run green arrow to run your emulator. Then, close the
dialog box.
As you know, it is difficult to write a topic about troubleshooting this type of problems
because each computer has different hardware, Windows O.S, Windows updates,
security software, as well as different settings. Therefore, if you still have this problem
with running your Android Studio emulator, you may check the following link:
https://developer.android.com/studio/run/emulator-acceleration#vm-windows
Or check https://stackoverflow.com web site, and try to find a solution for your case.
Now, you may check Flutter doctor command again. Test flutter doctor command
through command prompt or your Android Studio Terminal console which is located at
the status bar of Android Studio. The run result is illustrated in the following figure.
4-30
Introduction to Flutter AFD-200
To run your app, click Run menu, then click Run. Also, you may click the Run
button on the tool bar.
The run result will be as follows:
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
Replace the command _counter++; with _counter--; then run your app using
Run button.
Then, test your app again.
4-31
Flutter ™ Application Development
Flutter’s hot reload feature helps you quickly and easily experiment, build UIs, add
features, and fix bugs. Hot reload works by injecting updated source code files into
the running Dart Virtual Machine (VM). After the VM updates classes with newer
versions of fields and functions, the Flutter framework automatically rebuilds your
app structure, allowing you to quickly view the effects of your changes.
Example:
In the previous code, replace in your Dart code the last line of code as illustrated in
the following code:
child: Icon(Icons.add),
with
child: Icon(Icons.favorite),
Then, click the hot reload button , and check the changes in your phone emulator.
Also, you may change this button using the following suggestions:
child: Icon(Icons.battery_charging_full)
Or
child: Icon(Icons.call),
The emulator toolbar provides access to a range of options relating to the appearance
and behavior of the emulator environment as illustrated in the following figure:
4-32
Introduction to Flutter AFD-200
For example, the following is a description of the role of some of these buttons:
More (Extended Controls): Displays the extended controls panel, allowing for the
configuration of options such as simulated location and telephony activity, battery
strength, cellular network type and fingerprint identification.
4-33
Flutter ™ Application Development
As illustrated in the previous figure, you already have Pixel 2 as Android emulator.
Now, you will install another Android phone emulator called Nexus and know why it
is better than using Pixel emulator in testing your Flutter apps.
You will repeat the previous steps to add a new Android emulator to Android Studio
as follows:
1- In the Android Virtual Device Manager dialog box, click Create Virtual Device
2-Then, Nexus 6 , and click Next
4-34
Introduction to Flutter AFD-200
3- Select Oreo (Android 8.1), and click Download. After completing the download
process, Click Next, you will get a list of the virtual devices or Android emulator
which you can run and test your Android apps.
4- Click the pencil icon which is related to the Nexus 6 API 27 to edit this emulator
configurations. You will get the following dialog box:
4-35
Flutter ™ Application Development
In this type of emulators, you can select how graphics are rendered in the emulator. You
have three choices as follows:
•• Hardware - Use your computer graphics card for faster rendering (app running result).
We recommended you to use Nexus emulator in your test environment and this
course labs, because you can select hardware graphic type, and get a faster
rendering (run) result.
While, if you use Pixel emulator, you can’t change its graphic setting. Only the
automatic choice is available.
Now, we can say, “congratulations”! You have completed all of the steps in Windows
setup, and you are now ready to start building Flutter apps for Android development.
What is Xcode ?
Xcode is an IDE – an integrated development environment – created by Apple for
developing software for macOS, iOS, iPhone, iPad, Apple Watch, and Apple TV. It is
4-36
Introduction to Flutter AFD-200
the only officially-supported tool for creating and publishing apps to Apple’s app
store, and is designed for use by beginners and experienced developers. With Xcode,
you’ll be able to run Flutter apps on an iOS device or on the simulator. The Xcode is
available as a free download from the Mac Apple Store.
This means, when you use Android Studio on Mac computer, you can have Android
and iOS emulators to test your Flutter apps.
The follow figure displays what the default flutter app looks like with Android phone
(Nexus 6) and iOS phone (IPhone XR).
4-37
Flutter ™ Application Development
As you have seen in the previous figure, the Flutter app UI (user interface) in the two
simulators is almost the same. Only the title bar, which contains the name of the
application or the logo is different , where the default format is centered with iOS
phones, while with Android phones, it is on the left margin.
The question is, whether you can test your Flutter app code on iOS phones emulator
without the need to use a Mac computer, if your computer has Microsoft Windows
operating system?
This is an important question, because as a Flutter application developer, selecting this
programming language gives you the ability to create or maintain Android and iOS apps,
using the same codebase. Also, you must know what your app user interface will look
like on Android or iOS devices before publishing it to an Apple or Google store.
If your computer operating system is Mac, you can easily, through Android Studio,
install different types of Android emulators , and by default, when you install Xcode
from Apple store, an iOS emulator will be configured and added automatically to
your Android Studio emulators list.
Now , we can say, “yes,” even though you have a Microsoft operating system, you
can test your Flutter app and see what it will look like by performing the following
steps:
1- Go to https://github.com
2- Click Sign Up to create a GitHub account. Fill out your information , and then
click Next: Select a plan
3- Click Choose Free
4- Answer the complete setup questions, and then click Complete setup.
5- You will get a message asking you “ Please verify an email address “. Login to
your email address, open GitHub email . Then click Verify email address.
6- Login to GitHub again using your username and password.
7- Click the plus sign on the upper right corner as illustrated in the following figure.
Then click New repository
4-38
Introduction to Flutter AFD-200
4-39
Flutter ™ Application Development
15- Inside the Commit Message text box type the following text : initial commit
Then, click the arrow which is beside Commit button, and then select Commit and
Push .. as illustrated in the following figure:
4-40
Introduction to Flutter AFD-200
16- If you are asked to enter your GitHub user name or email address, enter them,
and then click OK.
17- You will get the following figure. Click Define remote
18- In the following dialog box, enter your GitHub repository URL as illustrated in the
following figure, then click OK.
19- You will get the following dialog box asking you to enter your GitHub user name
and password. Enter your credentials. Then click Log In.
4-41
Flutter ™ Application Development
20- Then, you will get the following figure. Click Push
21- You will get the following notification in your Android Studio notification area.
22- As you see in the following figure, your app has been pushed to your GitHub
repository
4-42
Introduction to Flutter AFD-200
If you click lib folder, you will get the Dart files as illustrated in the following figure:
If click the main.dart file, you will get the Dart file content
23- Run your Flutter app using your Android emulator (important step).
24- After running your app, click Flutter Inspector on the right side of Android Studio
as illustrated in the following figure:
25- Click Platform Android, and then select iOS as illustrated in the following figure:
4-43
Flutter ™ Application Development
Now, check your emulator. You will find your app navigation bar content has moved
to the center of your emulator. This means that your emulator run output of your
app will give you the same result as it runs on an iOS device. You can switch
between Android and iOS, and check what your app looks like .
The following figure displays your code in the same emulator but with two different
platform choices (Android & iOS):
This means if you have a Microsoft computer, you don’t need to buy a Mac
computer to test your Flutter apps on iOS phones. The previous technique gives you
an idea about how your app will run and what its user interface looks like.
If you have a Mac computer, you can test your Flutter app on Android and iOS
emulators without the need to follow the previous technique when you want to test
your app on an Android emulator.
4-44
Introduction to Flutter AFD-200
4-45
Flutter ™ Application Development
Also, you may change the font size by clicking the Editor option on the left side of
the previous dialog box and then clicking Font. Here, you may also select the font
type and size you are most comfortable with. Then click Ok.
As illustrated in the following figure, make sure Perform hot reload on save option
is checked, which is selected by default. Also, select Format code on save, which
means that every single time you will click the save button or select the Save All
option from the File menu, the code will be reformatted in the standard format. Be
sure these two choices are selected. Then click OK.
To test the last choice, for example, move some code to the right side using Tab or
space bar key, then click File → Save All, you will find that the code has returned to
its original location or format. This makes the code easier to read. Also, you can get
the same result if you right click the code. Then select Reformat Code with dartfmt
of the shortcut menu.
4-46
Introduction to Flutter AFD-200
In the project pane, as illustrated in the following figure, you will find a folder for your
Android app and another folder for your iOS app.
When you are creating your Flutter app using Android Studio, it will automatically
create your iOS and Android apps in the background, and update them as you create
your Flutter app.
Also, you may use Collapse All button as illustrated in the following figure to
collapse all the open project files and folders. In addition, when you click the Scroll
from Source button, you will locate which file of the Flutter project files are open or
show you where you currently are inside your project structure.
4-47
Flutter ™ Application Development
Also, if you navigate the Dart code, you will find a blue square at the margin as
illustrated in the following figure. This helps you to locate the part of the code which is
related to the blue color. If you change the color to red, this blue square will turn red.
Dart Analysis
Let us make a small error in this code by replacing the previous line of code which is related to
the blue color with the following code: primarySwatch: Colors.+blue, here I added only a
“+” sign. Then, I clicked run button. If you click the Dart Analysis at the status bar of an Android
Studio as illustrated in the following figure, you will see the error description and also see
which line number of the code the error is in. Also, if you double click the red error message, the
mouse pointer will move automatically to the error location. In addition, in almost cases the
description field in the Dart Analysis console gives you an idea about the reason of the error.
4-48
Introduction to Flutter AFD-200
Flutter Outline
The Flutter outline is on the right side of Android Studio as illustrated in the
following figure. It displays the tree structure of your codebase. This outline is really
helpful especially when you have a long file full of code and you need to locate a
specific part such as a text, row, column, an image , a button etc... So, you can just
click on the part you need in the Flutter outline console, and it will highlight that
part inside your code on the left side. This is really useful when you are navigating
around your code and checking what your code looks like at a glance.
Flutter Inspector
The Flutter Inspector is on the right side of an Android Studio as illustrated in the
following figure. It is a powerful tool for visualizing and exploring Flutter widget
trees (such as text, buttons, and toggles). The Flutter framework uses widgets as
the core building block for anything from controls, to layout (such as centering,
padding, rows, and columns). The inspector helps you visualize and explore Flutter
widget trees, and can also be used for the following:
4-49
Flutter ™ Application Development
To test the effect of Flutter inspector, use the same code of lesson 4 and make sure
that your app is running on a device (emulator or physical device).
For example, if you click on the FloatingActionButton on the Flutter Inspector, you
will notice a highlight on your emulator as illustrated in the following figure. You will
also get all the properties of this button such as color, font size, and other properties
on the lower part of the Flutter inspector pane.
Also, the widget mode button on the Flutter Inspector, as illustrated in the following figure
has an amazing and important role. This button allows you to select anything you see in
the running phone emulator to locate it inside the code. For example, scroll up the Android
Studio and click the mouse pointer on the first line of your code, click the widget mode
4-50
Introduction to Flutter AFD-200
button once, then click the text “You have pushed the button these many times:” on your
phone emulator, your Android Studio will scroll down to show you the part of the code which
includes this text, or it will highlight to you the part of your code which actually created this
part (text). To test another part of your app, just click the lens icon on your phone emulator,
and then test another widget such as the floating button.
Also, if you click the Debug Paint button on the Flutter Inspector, you will add on
your phone emulator visual debugging hints to the rendering that displays borders,
padding, alignment, and spacers. This helps in designing and improving your app
interfaces.
For more information about Flutter inspector tool, check the following web site:
https://flutter.dev/docs/development/tools/devtools/inspector
Keep in mind, you cannot test a Flutter app on a connected IPhone device if your
computer O.S is Microsoft Windows. However, if your computer is Mac, you can test
your app on a connected Android or IPhone device.
4-51
Flutter ™ Application Development
4-52
Introduction to Flutter AFD-200
2- Press 7 times on the Build number till you get the following message: “ Developer
mode has been turned on.” as illustrated in the following figure:
4-53
Flutter ™ Application Development
3- Go to Settings, then you will find Developer options has been added. Select
Developer options. Be sure this option is On. Then enable USB debugging as
illustrated in the following figures:
4- Select OK for this message: “Allow USB debugging?” as illustrated in the following figure:
5- Now, your Android phone is ready to be connected to your computer using a USB
cable and run your Flutter app. Before following this step, it is important to pay
attention to the following note:
Not all USB cables are created equally. Some cables can transfer power without being able to
transfer data. So, even if you see your device charging, it doesn’t mean that the cable can transfer
the data to allow your phone to be recognized by your computer. Ideally, find the original cable
4-54
Introduction to Flutter AFD-200
that came with your device. This usually allows both charging as well as data transfer.
Now, connect your phone through a USB cable to your computer, and check the computer
icon on your computer. If your phone appears as storage on your computer, this means that
your phone is connected successfully to your computer and it can share data with it.
If you are sure that your USB cable is a good cable to transfer data, and you got a message
on your computer notification area displaying that there is a problem in configuring your
phone driver with your computer operating system, this means you that you must install
your phone USB driver (software) to connect your phone to your computer using a USB
cable. To do this, just type on Google search “install Samsung USB driver for Windows”, or
use your Android phone type, and then install this driver on your computer. Disconnect, and
then connect your phone again to your computer, and accept any warning messages that
appear on your phone regarding connecting your phone through the USB.
6- Now, check your emulators list on your Android Studio. You will find your phone
name (SM :Samsung) as illustrated in the following figure:
7- Click Run on your Android Studio. Then your Flutter app will run on your
connected Android phone as illustrated in the following figure:
4-55
Flutter ™ Application Development
All Android settings which you applied before on Android Studio Android emulator
can be applied on your connected Android phone such as the Hot Reload, and
Enable Select Widget Mode (available at the Flutter Inspector Window).
4-56
Introduction to Flutter AFD-200
The debug mode banner will be removed directly from your phone emulator without
the need to run your app again because this part is not related to your app code.
However, it is related to your phone emulator settings.
4-57
Flutter ™ Application Development
Similarly, when designing your Flutter app user interface, you should arrange your
app content inside rows and columns widgets. This will guarantee that you will get
the same UI or layout even though the device type or screen size which will be used
in running your app. In Flutter development, usually we use rows and columns as
main widgets.
The core of Flutter’s layout mechanism is widgets. In Flutter, almost everything is a
widget-even layout models are widgets. The images, icons, menus, buttons and text
that you see in any Android or iOS app are represented in Flutter development as
widgets. But things you don’t see are also widgets, such as the rows, columns, and
grids that arrange, constrain, and align the visible widgets.
Row and Column are classes that contain and layout widgets. Widgets inside of
a Row or Column are called children, and Row and Column widgets are referred to
as parents. Row lays out its widgets horizontally, and Column lays out its widgets
vertically.
The following figure displays how UI/UX app designer starts with designing the
app wireframes or prototypes which are created for the purpose of arranging
app elements to best accomplish a particular purpose. The purpose is usually to
communicate the business objective as well as a creative idea.
In Flutter development, almost each of these elements (widgets) will be arranged inside
columns and rows.
4-58
Introduction to Flutter AFD-200
4-59
Flutter ™ Application Development
7- You will get the default Flutter project which is created by the Flutter team, and
included by default a simple counter app. The default location of this main.dart file
is : lesson_ 04 → lib → main.dart as illustrated in the following figure:
8- Delete all the code lines of main.dart except the first lines, then add the main
function . This means that you must have the following code only in main.dart file:
import 'package:flutter/material.dart';
void main() {
All your app structure and content will be between the two braces { } of the main()
function.
In Flutter, almost everything is a widget—even layout models are widgets. Let us start
with Text widget by adding the following code:
import 'package:flutter/material.dart';
void main() {
Text('Hello, world!');
}
4-60
Introduction to Flutter AFD-200
If you run your app, you will get an empty app as illustrated in the following figure:
To attach the Flutter widgets to the device screen , you need to use runApp function.
All widgets will belong to this function as follows:
runApp (
Widget app
);
import 'package:flutter/material.dart';
void main() {
runApp(Text('Hello, world!'));
}
4-61
Flutter ™ Application Development
10- Run your app. The run output will be as illustrated in the following figure. This run output
displays: No Directionality widget found. This means that this text widget must have a
specific format that determines its location on the device screen especially the alignment
format (center, left, or right), and if this text has “right to left” or “left to right” format.
11- Now, we will add Center widget as a parent widget for the Text widget. This means
that the Text widget will be a child widget. Also, we must add more properties for this
Text widget as follows:
import 'package:flutter/material.dart';
void main() {
runApp(
Center(child:Text('Hello,world!',textDirection:
TextDirection.ltr)));
}
Note : ltr means : left to right , while you can use rtl for right to left.
4-62
Introduction to Flutter AFD-200
13- Now, all your code is on the same line, and it is really hard to distinguish which
widget descends from the other. So, how can you make this easier?
Well, by installing Flutter and Dart packages, we automatically get access to a reformat called
Dartfmt (Dart Format). This feature is really helpful; however, you will have to help it, so it will help
you better. The Flutter team advises that whenever you create a widget which has parentheses
or round brackets, add a comma after every round bracket. If you do this, when you Save or
when you right click the code and select Reformat Code with Dartfmt option, the code will
automatically be formatted showing an indented and more organized structure.
After adding a comma after each round bracket, right click the code, and select
Reformat Code with Dartfmt option. The code will be as follows:
4-63
Flutter ™ Application Development
As you see here, this app run output has a poor layout because it does not have any
format such as app title bar, buttons or others. To improve your app interactivity, you
don’t need to create each button, app bar , icon or other items manually by writing
a specific code for each. Instead, Flutter has a lot of widgets to work as templates
which are ready to add and customize to your app.
Think of a Widget as a visual component (or a component that interacts with the
visual aspect of an application). When you need to build anything that directly or
indirectly is in relation with the layout, you are using Widgets. Flutter provides a
number of widgets that help you build apps that follow Material Design.
Widgets are organized in tree structure(s). A widget that contains other widgets is
called parent Widget (or Widget container). Widgets which are contained in a parent
Widget are called children Widgets.
14- Now, using the previous code, you will add a MaterialApp widget to our app
code, then all other app widgets will be within or related to this class. Also, you will
add “home” widget which is the route that is displayed first, when the application is
started normally. The code will be as follows:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Center(
child: Text('Hello, world!', textDirection: TextDirection.ltr),
),
));
}
4-64
Introduction to Flutter AFD-200
This app widget tree is represented by the following diagram. For example, in this
widget tree, the Center widget is the partner widget for Text widget.
Can you imagine if you design an app that has this user interface, what will be your
customer feedback?
4-65
Flutter ™ Application Development
Lab 4
Replace Colors.blue with Colors.green , then click the Flutter Hot Reload button , and
check this change take effect on your phone emulator. You will find that the blue color
parts of your app change to green color. Also, the blue square is now green.
10- Click on Flutter Inspector tab, which is on the right side of Android Studio, then
click on Select Widget Mode button.
4-66
Introduction to Flutter AFD-200
11- On your phone emulator, click the text : You have pushed the button this many times:
12- Check your code. You will find the following part of code has been selected:
13- Replace this text : “You have pushed the button this many times:” with your
name , then click the Flutter Hot Reload button.
14- Click the Widget Mode button on the Flutter Inspector window again to disable its effect.
4-67
Flutter Widgets Fundamentals AFD-200
5-1
Flutter ™ Application Development
Scaffold Widget
When you want to create a Flutter app, you need to configure a lot of widgets and
change their format. You don’t need to create everything from scratch. You can
easily add the Scaffold class or widget to your app. This class implements the basic
material design visual layout structure for our app. This class provides application
programming interface for displaying drawers, snack bars, bottom sheets , and
other Flutter widgets.
This Scaffold() widget works as a container for other Flutter widgets, such as app body,
which will include the app content and AppBar as illustrated in the following figure:
Example:
In the following example, you will create a small Flutter app using the
Scaffold widget as a main parent for all your app interface widgets. To create this
app, perform the following steps:
5-2
Flutter Widgets Fundamentals AFD-200
4- Type : scaffold_widget for Project Name , and create a new folder : Lesson_05 for
Project Location. Click Next.
5- Type : androidatc.com for Company domain, and then click Finish
6- Open main.dart file, delete all the code , and type the following code :
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Text('Hello, world!', textDirection: TextDirection.
ltr),
),
),
);
}
5-3
Flutter ™ Application Development
8- As you see in the previous figure, the text “Hello, world!” appears at the top left
corner of the app interface, because this is the text default alignment format of the
Text widget. If you want to move this Text widget content to the center of your
app interface, configure this Text widget as a child widget of the Center widget, as
illustrated in the following code:
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Center(
child: Text('Hello, world!', textDirection:
TextDirection.ltr),
),),
),
);
}
5-4
Flutter Widgets Fundamentals AFD-200
As you see here, each widget performs a variety of roles. The Text widget is
responsible for displaying and styling text . The Center widget is responsible for
aligning objects in the center. Also, the MaterialApp is similar to grandpa of all the
widgets because it usually sits at the top of the code, and everything that you build
is a material app. Later in this lesson, you will learn more about how to control the
position of your app items.
9- Now, you can add more properties for your app widgets. Here in this app, you will
add some properties for the AppBar widget , for this widget, you can add the title
property, that is a Text widget. In addition, you may add some format to this Title
such as adding the center Title, and backgroundColor properties as illustrated in the
following figure:
5-5
Flutter ™ Application Development
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My First App'),
centerTitle: true,
backgroundColor: Colors.green),
body: Center(
child: Text('Hello, world!', textDirection: TextDirection.ltr),
),
),
),
);
}
10- Run your app, and you will get the following:
5-6
Flutter Widgets Fundamentals AFD-200
As you see in the previous figure, the AppBar widget has some properties such as
backgroundColor which changes your app title bar color. To get more information
about colors list check the following web site:
https://material.io/design/color and check the color list at the end of this web page. You will
find the gradients of each color is from 50 until 900 , this means you can control more in the
color gradients by adding a value for each color between 100 and 900 between two square
brackets (you can start with 50 , 100, 200 , ...900). For example, in the previous code replace
backgroundColor: Colors.green
with
backgroundColor: Colors.green[900]
You will get a dark green color , while if you use 100 , you will get a light green color.
5-7
Flutter ™ Application Development
11- Assume that you want to change the background color of your Scaffold widget
(appBar and body). You can do that easily by adding the following property to your
Scaffold widget as illustrated in the highlighted part of following code:
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
backgroundColor: Colors.amberAccent,
appBar: AppBar(
title: Text('My First App'),
centerTitle: true,
backgroundColor: Colors.green[500]),
body: Center(
child: Text('Hello,world!',textDirection:TextDirection.ltr),
),
),
),
);
}
Image Widget
This class or widget is used to display an image in Flutter app. In Flutter , the
following image formats are supported: JPEG, PNG, GIF, Animated GIF, WebP,
Animated WebP, BMP, and WBMP.
You can add image to your Flutter app using different sources. In this lesson you
will add an image using asset and network sources.
12- Continue using the same code previously. To add an image to your app, add
Image widget to your code with the source or the path where this image exists.
For example, if you want to add a network image, you should have the URL of this
image. To do that, go to the web site which has this image, and then right click this
image. Then, select Open image in new tab, then copy this image URL.
For example, go to Android ATC web site (www.androidatc.com), right click the
5-8
Flutter Widgets Fundamentals AFD-200
Android ATC logo, and then select: “Open image in new tab”. Go to this new tab and
copy the URL.
In this example the logo URL is:
https://androidatc.com/template/style/img/Android-ATC-Logo.jpg
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
backgroundColor: Colors.amberAccent,
appBar: AppBar(
title: Text('My First App'),
centerTitle: true,
backgroundColor: Colors.green[500]),
body: Center(
child: Image(
image: NetworkImage('https://androidatc.com/template/style/img/
Android-ATC-Logo.jpg')),
),
),
));
}
Before run this app, try to open Google web site using your phone emulator to be
sure that your phone emulator has Internet connection and your phone emulator
web browser is working fine.
5-9
Flutter ™ Application Development
When you run your app, you should get the following run output:
This method is superior, because your app users will use local images, and they
don’t need to connect to the internet to see each image in your app interfaces,
especially if your app is designed to work offline.
Continue to use the pervious code to add an asset image. Please perform the following steps:
5-10
Flutter Widgets Fundamentals AFD-200
14- Right click your Flutter project name (lesson_05) → New → Directory. Type images
for the directory name, and then click OK as illustrated in the following figure:
Remember that this folder is created to include all your app images.
15- Now, to add one or more images to this folder, just copy your images from your
hard disk and then paste them in this folder. Very easy right !!
In this example, you will copy the “AndroidATC.png” image from our lab files older:
Lab Source Files\Images (check your hard disk , and if you don’t have this folder
on your computer, check with your trainer or contact Android ATC support team at:
[email protected]) then paste this image in your app images folder which
you created in the previous step.
When you do this, you will get the following dialog box, just click OK to confirm.
Note: You can select many images , select copy , and then paste them in your
images folder in one step.
5-11
Flutter ™ Application Development
16- Now, you should configure your Flutter app to the default location (folder) of the images
in this app. To do this you must configure the pubspec.yaml file which is an important part
of your app files. This file location is illustrated in the previous figure. This file is the most
important file in any Flutter project because it includes all your Flutter app configurations. It
is the place where you provide all the required dependencies of your Flutter project. This file
is written using YAML language (Yaml ain’t markup language).
You have to be really careful when you are making changes in this pubspec.yaml file
code, because
in JAML language, almost each configuration consists of a parent and child level
are configured by an indent, and is each indent level is represented by two spaces.
Therefore, be careful about indentation in this YAML file.
To configure the assets, double click pubspec.yaml file, and then scroll down until
5-12
Flutter Widgets Fundamentals AFD-200
you find the part which is related to the assets configurations as illustrated in the
following figure:
17- Delete ONLY the hash sign for assets: and -images/a_dot_burr.jpeg lines. Also,
delete the last line : -images/a_dot_ham.jpeg.
18- In pubspec.yaml file, replace the image file name “ a_dot_burr.jpeg” with “AndroidATC.
png” or your image file which you pasted in the images folder, and move or indent the
“-images/AndroidATC.png” two spaces of assents: as illustrated in the following figure:
19- Click Packages get at the top of pubspec.yaml file content as illustrated in the
following figure:
20- In the main.dart file, delete the part which is related to add the image form
network which is illustrated in the following code:
image: NetworkImage(
'https://androidatc.com/template/style/img/Android-ATC-Logo.jpg')
5-13
Flutter ™ Application Development
21- To add the image which you added to images folder, use the AssetImage class
as it is illustrated in the grey highlighted part of the following code:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
backgroundColor: Colors.amberAccent,
appBar: AppBar(
title: Text('My First App'),
centerTitle: true,
backgroundColor: Colors.green[500]),
body: Center(
child: Image(image: AssetImage('images/AndroidATC.png'),
),
),
),
));
}
22- Stop your app , and then Run it again. Your image will be added to your app as
illustrated in the following figure:
5-14
Flutter Widgets Fundamentals AFD-200
23- Assume that you want to add 10 images or more to your app images folder. Do
you think there is another way to add these images to your app without the need to
add them line by line in your app pubspec.yaml file?
The answer is Yes !!. you only have to add the images folder name with a forward
slash “/” in the pubspec.yaml file as illustrated in the following figure, then you can
add your images to your app files using AssetImage widget.
Container Widget
When we want to have full control in a location when it comes to width and height
of any Flutter widget, we use the Container widget as a parent widget and configure
the other widget which we want to control as a child widget. You may add a lot
of properties to your Container widget such as background color, size, padding,
margins, borders or the shape of text, and other properties.
The Container is a widget class that allows you to customize, compose, decorate
and position its child widget. Container widget is similar to DIV tag in HTML.
Now, you will continue using your previous code in lesson 5, and check the benefit
of using the Container widget in your app.
24- Delete the part which is related to the image. Then, you will have the following code:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
backgroundColor: Colors.amberAccent,
appBar: AppBar(
title: Text('My First App'),
5-15
Flutter ™ Application Development
centerTitle: true,
backgroundColor: Colors.green[500]),
),
));
}
And when you run your app, you will get the following:
25- Add to your app a Container widget with a grey color property. The code will be
as follows:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
backgroundColor: Colors.amberAccent,
appBar: AppBar(
title: Text('My First App'),
centerTitle: true,
5-16
Flutter Widgets Fundamentals AFD-200
backgroundColor: Colors.green[500]),
body: Container(
color: Colors.grey,
)),
));
}
Run your app. As you see in the following figure, the body of the app interface has a
grey background color :
In the previous code, the Container widget did not include any child widget yet, and its
effect covered all the app interface body. While when this Container widget has a child
widget such as Text widget, it will try to be as small as possible. The following code
displays how to add a Text widget as a child widget of a Container widget:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
backgroundColor: Colors.amberAccent,
appBar: AppBar(
5-17
Flutter ™ Application Development
body: Container(
color: Colors.grey,
child: Text('Welcome to Android ATC'),
)),
));
}
26- Run your app. As illustrated in the following figure, the Container widget has shrunk
to the size of the Text font size.
As you see here, the Container widget size shrinks to match the size of the child widget.
5-18
Flutter Widgets Fundamentals AFD-200
•• But if you add the color parameter, your child widget will get a background
color. Without anything else, the Container sizes itself to its child.
27- Add a comment sign to the AppBar widget and to all its related widgets as you
see in the following code:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
backgroundColor: Colors.amberAccent,
//appBar: AppBar(
// title: Text('My First App'),
//centerTitle: true,
//backgroundColor: Colors.green[500]),
body: Container(
color: Colors.grey,
child: Text('Welcome to Android ATC'),
)),
));
}
Now run your app again, and you will see in the following figures (Android and iOS
emulators), the container widget location at the top left and outside the app body area.
28- To be sure that the Container widget and its child of another widgets will be in a safe
area, and will appear inside the app body area, you will configure your Container widget
as a child widget of another widget. This is called SafeArea widget.
5-19
Flutter ™ Application Development
you want to embed in another widget and either click on the little yellow light
bulb (lamp) or press (Alt +Enter) on Windows or (Option + Return) on Mac and
you will get a shortcut menu as illustrated in the following figure. Select Wrap
with new widget , and then type SafeArea for the new widget.
Note : When you start typing the first letters of SafeArea widget name, select the
second choice as it is illustrated in the following figure:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
5-20
Flutter Widgets Fundamentals AFD-200
backgroundColor: Colors.amberAccent,
//appBar: AppBar(
// title: Text('My First App'),
//centerTitle: true,
//backgroundColor: Colors.green[500]),
body: SafeArea(
child: Container(
color: Colors.grey,
child: Text('Welcome to Android ATC'),
),
)),
));
}
As you see in the following figure, SafeArea widget added the necessary padding
to keep your widget from being blocked by the system status bar, notches, holes,
rounded corners and other “creative” features by manufacturers.
29- Change the size of your Container widget by adding the height and width
properties to your Container widget as it is illustrated in the following code:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
backgroundColor: Colors.amberAccent,
//appBar: AppBar(
// title: Text('My First App'),
//centerTitle: true,
//backgroundColor: Colors.green[500]),
body: SafeArea(
child: Container(
width: 200,
height: 70,
color: Colors.grey,
5-21
Flutter ™ Application Development
30- Use the margin property to add empty space that surrounds that Container
widget. The following is a part of code that is responsible for adding 30 pixels
margin for all directions (top, right, left, and bottom) in the Container widget.
child: Container(
margin: EdgeInsets.all(30),
width: 200,
height: 70,
color: Colors.grey,
child: Text('Welcome to Android ATC'),
),
31- Use the Container padding property to add empty space between the child
widget (Text) and the Container boundary as it is illustrated in the following code:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
backgroundColor: Colors.amberAccent,
//appBar: AppBar(
// title: Text('My First App'),
5-22
Flutter Widgets Fundamentals AFD-200
//centerTitle: true,
//backgroundColor: Colors.green[500]),
body: SafeArea(
child: Container(
padding: EdgeInsets.all(10.0),
margin: EdgeInsets.only(left: 30),
width: 200,
height: 70,
color: Colors.grey,
child: Text('Welcome to Android ATC'),
),
)),
));
}
32- With the decoration property, you may add a shape, like a circle, to your
Container. The decoration is by default, sized to the container’s child.
In this case, the Container fits the circle decoration to the narrowest parameter, the
Text widget’s height, as illustrated in the following code:
Note here , you must change the Container color property to comment.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
backgroundColor: Colors.amberAccent,
//appBar: AppBar(
// title: Text('My First App'),
//centerTitle: true,
//backgroundColor: Colors.green[500]),
body: SafeArea(
child: Container(
decoration: BoxDecoration(
color: Colors.green,
shape: BoxShape.circle,
),
padding: EdgeInsets.all(10.0),
margin: EdgeInsets.only(left: 30),
width: 200,
5-23
Flutter ™ Application Development
height: 70,
// color: Colors.grey,
child: Text('Welcome to Android ATC'),
),
)),
));
}
33- The transform property applies a slight rotation to your Container widget if you
add the following code to your Container widget:
transform: Matrix4.rotationZ(0.1),
5-24
Flutter Widgets Fundamentals AFD-200
However, the container widget can have only one child widget or object. Assume
that you want something that can take lots of children of widgets not just a single
widget. The easiest way to do this is using the rows and columns widgets.
Rows and Columns are classes that contain and lay out widgets. Widgets inside of
a Row or Column are called children widgets, and Rows and Columns are referred to as parent
widgets. Rows lay out their widgets horizontally, and Columns lay out their widgets vertically.
Continue using the previous code of this lesson. Within the next steps, you will learn
more about how to arrange your app content using Column and Row widgets.
34- Delete all the codes which are related to the Container and AppBar widgets.
Then you will have the following code:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
body: SafeArea(
)),
));
}
5-25
Flutter ™ Application Development
35- Add a Column widget as a child widget of the SafeArea widget as illustrated in
the following figure:
36- Instead of using a child command to add the content of Column widget, you will
use children because Column widget can include more than one widget.
To add children widgets to your Column widget, all your Column children widgets
must be between two square brackets as illustrated, in the following code:
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[],
)),
)),
);
}
5-26
Flutter Widgets Fundamentals AFD-200
37- Add two Text, and two Container widgets to the Column widget as illustrated in
the following code:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
Text('Data 1'),
Text ('Data 2'),
Container(
child: Text('Data 3'),
color: Colors.grey,
margin: EdgeInsets.only(left: 20.0),
height: 50.0,
width: 70.0,
),
Container(
child: Text('Data 4'),
color: Colors.amber,
margin: EdgeInsets.only(left: 20.0),
height: 50.0,
width: 70.0,
),
],
),
),
),
));
}
5-27
Flutter ™ Application Development
38- Currently your Column is laying out its children (Text and Container) from top to
bottom.
If you want to go the other direction instead, you can change its vertical direction
using the following property :
verticalDirection: VerticalDirection.up
The part of the code which is related to the column widget follows:
body: SafeArea(
child: Column(
verticalDirection: VerticalDirection.up,
children: <Widget>[
Text('Data 1'),
Text('Data 2'),
If you replace:
verticalDirection: VerticalDirection.up,
with:
verticalDirection: VerticalDirection.down,
5-28
Flutter Widgets Fundamentals AFD-200
verticalDirection: VerticalDirection.down,
40- If you want to change the spacing between your Column content (children
widgets), you may use the main axis alignment property. Here, because you are
working with Column widget, the main axis is the vertical axis as you will see in the
next topic (Layouts in Flutter).
Icon Widget
Icons are essential to many app user interfaces. They visually express objects,
actions and ideas. When done correctly, they communicate the core idea and intent
of a product or action, and they bring a lot of benefits to the app user interface,
such as saving screen real estate and enhancing aesthetic appeal. An app icon is a
design pattern that is familiar to users.
When you add an Icon widget to your Flutter app, you are actually calling a specific
code which represents this icon name, and it will draw all the sides and the edges
of the icon onto the app screen. Therefore, when you change the size of any of your
app icons, they will have the same high resolution quality.
You should know the icon name which you want to add to your Flutter app. This name
will be used to call the Icon class in your code. The following web site includes a lot of
icons which Google has made available for free: https://material.io/resources/icons.
5-29
Flutter ™ Application Development
shopping_cart fingerprint
alarm room
backup build
In the following code , you will add an icon, and change its color and size.
41- Delete the Row widget and all its content of other widgets. Then, you will have
the following code:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
body: SafeArea(
),
),
));
}
42- In the SafeArea widget , add a new Container widget. In the Container widget,
add an Icon widget with size and color properties as follows:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
body: SafeArea(
5-30
Flutter Widgets Fundamentals AFD-200
child: Container(
child: Icon(
Icons.shopping_cart,
size: 50,
color: Colors.green,
),
),
),
),
));
}
Try other icon names from the previous icon names table.
Layouts in Flutter
The core of Flutter layout mechanism is widgets. In Flutter, almost everything is a
widget—even layout models are widgets. The images, icons, and text that you see in
a Flutter app are all widgets. But things you don’t see are also widgets, such as the
rows, columns, and grids that arrange, constrain, and align the visible widgets.
You create a layout by composing widgets to build more complex widgets. You need
to have full control of the position for each item or widget in your app interfaces.
In this section of this lesson, we will focus on some important widgets properties
which help you have more control on your app layout. Some of these properties you
may have used before in this or previous lessons ; however, in this section we will
focus on them in details.
The first important thing you should know, is that you cannot apply directly apply
the layout format on any child widget such as Image , Text, Checkbox , ...etc .
5-31
Flutter ™ Application Development
Instead, you should apply the layout format on the parent widget which warps these
children widgets, such as Container, Column, Row, or another parent widget.
Container(
margin: EdgeInsets.symmetric(vertical: 60.0, horizontal: 100.0),
child: Text(
"Welcome",
style: TextStyle(fontSize: 20.0),
),
),
The following two figures display how the text looks like before and after using the
margin property:
Also, as illustrated in the following code , using the alignment property with
Container widget helps in making changes in the Text widget layout.
body: Container(
alignment: Alignment.topCenter,
child: Text("Flutter App"),
),
5-32
Flutter Widgets Fundamentals AFD-200
The following figure displays the text location when you apply each alignment
property value on the Container widget which is wrapped in the Text widget:
If you want to add padding around Row or Column content, it is a good idea to place
the Row or Column widget in a Container widget.
Row(
children: <Widget>[
Text(
'Hellow',
style: TextStyle(fontSize: 20.0),
),
Icon(Icons.settings_input_antenna),
],
)),
5-33
Flutter ™ Application Development
Container(
padding: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 10.0),
child: Row(
children: <Widget>[
Text(
'Hellow',
style: TextStyle(fontSize: 20.0),
),
Icon(Icons.settings_input_antenna),
],
),
padding: EdgeInsets.all(20.0),
padding: EdgeInsets.only(left:20,top:20,right:20,bottom:20),
Padding Widget
This widget is used to wrap a Column , Row , Container or other widgets. This
widget adds a padding size around the child widget.
5-34
Flutter Widgets Fundamentals AFD-200
For example, we usually build our app interface of a group of parents and children
widgets in tree structure, and we start with a Column widget then use Rows and
Containers as illustrated in the following example:
import 'package:flutter/material.dart';
5-35
Flutter ™ Application Development
However, if you double click the Column widget , and then press Alt + Enter ,or click
the orange lamp icon , you will get the following wrap choices:
Select Wrap with Padding , then the Padding widget will wrap your Column widget
and add 8 pixels around your Column widget contents.
5-36
Flutter Widgets Fundamentals AFD-200
}
}
The run output after using the Padding widget will be as follows:
SizedBox Widget
This widget helps us to have a specific width and/or height between widgets.
For example, the following code includes two Text widgets in the same row.
Row(
children: <Widget>[
Text('ABC',style:TextStyle(fontSize: 20.0),),
Text('XYZ',style:TextStyle(fontSize: 20.0),),
],
)
When you run this app , these two texts ( ABC & XYZ) will appear without any
horizontal space as illustrated in the following figure:
While when you use the SizeBox widget with a specific width between these two
Text widgets, it will be illustrated in the following code:
5-37
Flutter ™ Application Development
Row(
children: <Widget>[
Text('ABC',style:TextStyle(fontSize: 20.0),),
SizedBox(width: 40,),
Text('XYZ',style:TextStyle(fontSize: 20.0),),
],
)
Also, you may use this SizedBox widget to add some vertical space between two
Row widgets when you use the property of height.
Aligning widgets
You may control how a Row or Column widgets aligns its children using the
mainAxisAlignment and crossAxisAlignment properties. For a Row widget, as ,
illustrated in the following figure, the main axis runs horizontally and the cross axis
runs vertically. For a Column widget, the main axis runs vertically and the cross axis
runs horizontally:
5-38
Flutter Widgets Fundamentals AFD-200
Example:
1- Create a simple Flutter app including the following code:
import 'package:flutter/material.dart';
2- Then, run your app and replace the grey highlighted part of the code with the
following values :
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
5-39
Flutter ™ Application Development
Check the app run output result for each change. You should get the following run outputs:
3- Replace the Column with a Row in the previous code and check the following
aligning property values:
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
5-40
Flutter Widgets Fundamentals AFD-200
4- Try to use the properties below with the Row and Column widgets :
crossAxisAlignment: CrossAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
In Flutter Inspector window, and as illustrated in the following figure, click Debug Paint
button , and then check your phone emulator. You should get the vertical and horizontal
axis for your phone emulator. These axis help you align your column and row contents.
In lesson 7, you will learn more about other layout widgets such as Stack widget.
5-41
Flutter ™ Application Development
Card Widget
A Card class is a material design card. A card has slightly rounded corners and a
shadow.
A Card widget is a sheet of material used to represent some related information, for
example an album, a geographical location, a meal, contact details, etc.
This widget is similar to a Container widget , where it can include other children
widgets such as images, text , and others. However, with this widget you cannot use
the padding property to add space between the Card widget border and the card
children widgets or Card widget content. While you can use a Padding widget to do
this task as you will see in the next example.
Continue using the same main.dart file, and perform the following steps:
1- Delete all the previous code, and set the main.dart file content as follows:
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: SafeArea(
),
),
),
);
}
In this example, you will use the Card widget to get a design similar to the following
figure. As you see here, the Card widget will be the parent widget for all the children
widgets which are illustrated in the following figure. These children widgets are Row,
Image, Text , and SizeBox widgets.
5-42
Flutter Widgets Fundamentals AFD-200
2- First, you should add the image : pizza.png file in the images folder which is on
your Project navigation window using the copy and paste technique. You can find
this image in the images folder (check your lab file folder for this course on your
computer ). Then click Ok to confirm adding this image.
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: SafeArea(
child: Card(),
),
),
),
);
}
4- Add the Row widget as a child widget of the Card widget. Then, add the Text and
Image widgets as children widgets of the Row widget. Then, add the SizedBox widget to
make a space between the Image and Text widgets. The code will be as follows:
import 'package:flutter/material.dart';
void main() {
5-43
Flutter ™ Application Development
runApp(
MaterialApp(
home: Scaffold(
body: SafeArea(
child: Card(
child: Row(
children: <Widget>[
Image(
image: AssetImage('images/pizza.png'),
width: 100.0,
height: 100.0,
),
SizedBox(width: 20.0),
Text('Vegetable Pizza'),
],
),
),
),
),
),
);
}
5- You should add some properties to your Card widget such as color, margin, and border.
Also, you may change the style of your Text widget such change the font weight ,
size and color as illustrated in the following code:
5-44
Flutter Widgets Fundamentals AFD-200
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: SafeArea(
child: Card(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.
circular(15)),
margin: EdgeInsets.all(10.0),
color: Colors.deepOrangeAccent,
child: Row(
children: <Widget>[
Image(
image: AssetImage('images/pizza.png'),
width: 100.0,
height: 100.0,
),
SizedBox(width: 20.0),
Text('Vegetable Pizza',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 30.0),),
],
),
),
),
),
),
);
}
5-45
Flutter ™ Application Development
In this part of the lesson, you will configure your app icon for iOS and Android
devices. Also, this icon will represent your app on your customers’ smart devices
(iOS or Android), and in Apple and Google Stores.
You may ask a graphic designer to create your app icon, use Adobe Illustrator
software, search on Google images, or use a free logo design software web site.
The App icon is an image which has an extension JPEG or PNG. It is better to use
PNG image format because PNG supports transparency while JPEG does not.
I will use “AndroidATC.png” image in creating the icon image for this Flutter app for
Android and iOS apps.
The images folder is a part of the lab files folder of this course. This folder
includes this image and other images. If you do not find this folder on your
computer, please contact our support team at [email protected],
and ask them about the lab files for Flutter application development course.
To create an app icon for Android and iOS apps, you need to have a PNG image, and then it is
easier to use a free web site such as : appicon.co or any other web site to generate icons for
your iOS and Android apps. To add an icon image for your app, perform the following steps:
1- Go to appicon.co web site, and as you see in the following figure. Select only
IPhone and Android.
5-46
Flutter Widgets Fundamentals AFD-200
2- Click the image box, select your image as illustrated in the following figure, and
then click Generate button.
3- This web site will automatically download a compressed file including the Android
and iOS app icons.
If you have any problem with this step or in this web site, these icon files are in the
images folder with the lab files folder inside a folder called AppIcons.zip.
4- Right click the AppIcons.zip file, and then select Extract files. Extract the content
of this folder inside a new folder called : Icons in the following path C:\Icons or with
any other name and at any other location on your computer. You will have two folders.
“android” folder which includes the Android app icons , and “ Assets.xcassets” folder
which includes the iOS app folders as illustrated in the following figure:
Remember, when you are building your Flutter app code in main.dart file or in
another file, the Android Studio simultaneously builds your Android app files
in “android” folder and your iOS app files in the “ios” folder as illustrated in the
following figure:
5-47
Flutter ™ Application Development
This means you should add your Android app icon inside the “android” folder, and
your iOS app icon inside the “ios” folder.
5- To add an icon to your Android app, at the Project console, and as illustrated in
the following figure, go to android → app → src → main → res
You will find the default app icons in different sizes , and as you see here, the Flutter
icon is the default app icon for your app. To configure your app icons, just replace
these icons (images) with your icons which you got in the previous step. To do that:
Right click “res” folder , and then select Show in Explorer for Windows, or select
Reveal in Finder for Mac O.S.
6- Open res folder, and Delete the folders which start with mipmap (mipmap-hdpi , mipmap-
mdpi, mipmap-xhdpi, mipmap-xxhdpi,and mipmap-xxxhdpi). There are five folders.
7- Now, you will add your icons folders to the same location from where you deleted
the previous folders. Go to : C:\Icons\android , Copy all folders (five folders) , and
5-48
Flutter Widgets Fundamentals AFD-200
Check your res folder using your Android Studio (android → app → src → main → res) ,
and you should find that your Android app uses the new app icons.
Now, you will repeat the same steps as followed previously, but for iOS app as follows:
8- On Android Studio, in Project console, go to:
ios → Runner → Assets.xcassets → AppIcon.appiconset
You will find all the iOS default icons in different sizes. Right click : AppIcon.appiconset
and then select Show in Explorer for Windows, or select Reveal in Finder for Mac O.S.
9- Open AppIcon.appiconset folder, and Delete all these folder files.
10- Copy all your iOS files (images and files) which you have at this path :
C:\Icons\Assets.xcassets\AppIcon.appiconset, and then Paste them inside the
AppIcon.appiconset folder.
Now, check your iOS app icons which are available in the following path :
ios → Runner → Assets.xcassets → AppIcon.appiconset, you should find your icons.
11- To test if your phone emulator is using your app icon, just stop your App by clicking
the stop button as illustrated in the following figure, and then run your app again.
12- Click your phone emulator home button, and check your app list. You will find your
app icon with your phone emulator apps list as illustrated in the following figure:
13- For Android app only, if you want to make more changes in your app icon such
as making the image stretches all the icon circle. In Android Studio, right click the
android → New → Image Asset
14- You will get the following figure. Click the folder icon at the Path: and select your
original PNG image which you have used to generate the icons. In the Scaling part,
slide the arrow to resize your image and to get the desired size of your icon. Be sure
your image is still inside the circle, click Next , and then click Finish.
5-49
Flutter ™ Application Development
15- Now, stop your app , and then run it again. You will find the new Android app icon
image filling more space of the circle icon, and it is clearer.
To get more information about Google Play icon design specifications, check the
following URL:
https://developer.android.com/google-play/resources/icon-design-specifications.
To get more information about Apple icon design specifications, check the following URL:
https://developer.apple.com/design/human-interface-guidelines/ios/icons-and-
images/app-icon
5-50
Flutter Widgets Fundamentals AFD-200
Hot reload allows you to almost instantaneously see your changes in your emulator
or on your device that you are testing it on. This means, you don’t need to stop and
then re-run your app.
Most types of code changes can be hot reloaded.
Example:
Continue using the previous code in lesson05 project, and perform the following
steps :
1- Make your code as follows, and delete the other code:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
backgroundColor: Colors.green,
body: Container(),
),
));
}
2- Stop and then run your app using the Android Studio toolbar as illustrated in the
following figure. You will get an empty app with a green background.
3- Now, change your app background color to red color in your app code.
Replace :
backgroundColor: Colors.green,
with:
backgroundColor: Colors.red,
5-51
Flutter ™ Application Development
And then, click the hot reload button. No change will occur in your app background
color. It will still be green. However, if you stop your app, and run it again, the
background color will change to red.
Why this is happening ? This will be explained in this section.
In the previous example, you modified the code of the Scaffold widget , but this
widget version did not change. Therefore, when you clicked the hot reload button
on Android Studio tools, Flutter SDK instead of reloading your app from scratch, it
searched on your app whether if there is any change in your widgets versions to
push these changes only to your running emulator.
If you change your widget status to Stateless widget, this will make your widget
version compatible with any change to its properties. To change the Scaffold widget
to stateless widget, perform the following change in your code.
1- Type outside the main function : st , and then select stless from the shortcut
menu to create a new Stateless widget as illustrated in the following figure:
5-52
Flutter Widgets Fundamentals AFD-200
The next section of this lesson includes more information about the Stateful
.and Stateless widgets
MaterialApp(
home: Scaffold(
backgroundColor: Colors.green,
body: Container(),
),
));
4- Use paste command to replace your code with the Container(); widget in the
new stateless widget (MyApp). Delete the extra bracket in MyApp class.
import 'package:flutter/material.dart';
void main() {
runApp(
}
5-53
Flutter ™ Application Development
5- Now , add your class name “MyApp” to the main() function as illustrated in the
grey highlighted part of the following code:
void main() {
runApp(
MyApp(),
);
}
6- Now, you should stop your app, and then run it again to be sure that the app
which is running on your emulator is MyApp.
7- Change the background color of the Scaffold widget to red color, and then click
the hot reload button. Then, you will find that your app user interface has directly
been changed to red .
Also, you can use the hot reload button which is available at the run console as
illustrated in the following figure:
Now, after you make these changes, you can get the same result of hot reload if you
save your app (Crtl + S for Windows) or (command + S for Mac).
5-54
Flutter Widgets Fundamentals AFD-200
Hot Restart
In the same Run console, there is a Hot Restart button. This option resets your
app state such as delete any changes in a form data input or counter status, and
starts your app from the beginning, without the need to upload all the app data
from Android Studio to your emulator. It takes time less than stopping your app and
restarting it.
If you are testing something like a form, where you don’t want to lose the data that
you have used to test the app, but you want to make some changes in your app user
interface, just click the hot reload, and then you will not lose this data. However, if
you click hot restart, the changes will be tested, but you will lose this data.
A stateless widget never changes. Icon, IconButton, and Text are examples of
stateless widgets. Stateless widgets subclass StatelessWidget.
A widget’s state is stored in a State object, separating the widget’s state from
its appearance. The state consists of values that can change, like a checkbox is
checked. When the widget’s state changes, the state object calls setState(), telling
the framework to redraw the widget.
In the next example, you will see how Stateful widget works.
When the widget’s state changes, the state object calls setState(), telling the
framework to redraw the widget.
5-55
Flutter ™ Application Development
Example:
In the following example , you will create a simple Flutter app to test the difference
between the Stateful and Stateless widgets.
6- Open main.dart file. and delete all the code , and Type the flowing code :
import 'package:flutter/material.dart';
void main() {
runApp(
MyApp (),
);
}
Then, add a stateless widget by typing st , and then select stless of the shortcut
menu as illustrated in the following figure:
5-56
Flutter Widgets Fundamentals AFD-200
7- Name the Stateless widget : MyApp as illustrated in the grey highlighted part of
the following code:
import 'package:flutter/material.dart';
void main() {
runApp(
MyApp (),
);
}
8- Configure this app to use a Scaffold widget which includes the basic material
design of the visual layout structure of the flutter app. The code follows:
import 'package:flutter/material.dart';
void main() {
runApp(
MyApp(),
);
}
5-57
Flutter ™ Application Development
9- Add a Column widget as body of your app and wrap it with a Padding widget. The
code follows:
import 'package:flutter/material.dart';
void main() {
runApp(
MyApp(),
);
}
5-58
Flutter Widgets Fundamentals AFD-200
As you see, the Stateless widget with Text widget runs fine.
10- Now, in this step, you will add a button (Raised Button) to your app. In the next
lesson, you will learn in detail about the different types of buttons and how to
configure them. Now, in brief , by adding the following code you can add a Raised
button to your app:
RaisedButton(
child: Text('Click Me'),
onPressed: () { ),
)
The Text widget here represents the button title. When you press this button , the code
which you will type between the two braces {} of the onPressed method will run.
The following code includes a RaisedButton, and the onPressed method includes
an IF statement which depends on its work on an integer variable called x which
equals 1 , and it is configured outside the Stateless widget as illustrated in the grey
highlighted part of the following code:
import 'package:flutter/material.dart';
void main() {
runApp(
MyApp(),
);
}
int x = 1;
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Statfeul and Stateless Widgets'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
5-59
Flutter ™ Application Development
child: Column(
children: <Widget>[
Text('Welcome to Android ATC'),
Container(
child: RaisedButton(
child: Text('Click Me'),
onPressed: () {
if (x > 5) {
print("Hello, I am If statement ");
} else {
print("Hello, I am Else statement ");
}
},
),
)
],
),
)),
);
}
}
11- Run your app , you will get the following run output:
12- Click the button, you will get the following result on the run console:
5-60
Flutter Widgets Fundamentals AFD-200
13- Replace the value of the variable x with 40 , and then click the Hot Reload button
You will get the same run result : Hello, I am Else statement
This means that variable x still has value =1 in the app framework , because the hot
reload button reloaded only the stateless widget content of this app.
In the previous code, move the x variable to inside the MyApp stateless widget as
illustrated in the following figure:
int x = 40;
@override
Widget build(BuildContext context) {
return MaterialApp(
Now, click the Hot Reload button, and then click the Click Me button on your app,
and the result will be as follows:
Now, to know more about the difference between stateful and stateless widgets,
perform the following steps using the same previous app:
14- Right click your app directory, and then select New → New Directory . Type
images for the directory name, and then click OK.
15- Configure the pubspec.yaml file to use this images folder for app images as you
did previously in this lesson in the image widget section.
16- Open the Lab Source Files\Images on your computer, copy ( pizza1.png &
pizza2.png ) images , and then paste them in the images directory in Android Studio.
17- Delete the IF statement code , and add the Image widget as a child widget of the
Column widget.
5-61
Flutter ™ Application Development
import 'package:flutter/material.dart';
void main() {
runApp(
MyApp(),
);}
int x = 1;
Note that, the image value depends on the variable x , and x=1, then when you run this
app you will get the cheese pizza (pizza1.png) as illustrated in the following figure. But,
if x=2, this means that the vegetable pizza image (pizza2.png) will display.
5-62
Flutter Widgets Fundamentals AFD-200
18 - Add to the button action: setState() method and make it change the value
of variable x from 1 to 2 when the app user clicks this button. This means this app
contains dynamic contents now.
Make the code of this button as follows:
Container(
child: RaisedButton(
child: Text('Click Me'),
onPressed: () {
setState(() {
x = 2;
});
}),
),
Here, you will get a red underline with the setState method because you are using
StatelessWidget widget. Double click the StatelessWidget, click the orange lamp
icon , and then select Convert to StatefulWidget as illustrated in the following figure:
5-63
Flutter ™ Application Development
19- Run your app, and click the app button (Click Me) .
The setState method will update the app system framework with the new value of
variable x ; therefore, the image will be updated to pizza2.png.
We conclude that, if you are creating a user interface where the state of the widget
is not going to change (static content), then you should use a Stateless widget.
But, if your app content is interactive (dynamic content), such as a user taps on a
button or makes a connection with a database that produces changes or updates
on the app interface , then you need to use a stateful widget.
Flutter works with custom fonts and you can apply a custom font across an entire
app or to individual widgets. As you did before in this lesson in adding an image to
your app, you can do the same technique for importing a new font to your Flutter
project. This recipe creates an app that uses custom fonts with the following steps:
You can search about your desired font using the font name or category. For
example, as illustrated in the following figure, click Categories , and then select only
Handwriting category.
5-64
Flutter Widgets Fundamentals AFD-200
3- Click the pop up black rectangle window, and then click the download arrow to
download this font file as illustrated in the following figure:
4- Extract the downloaded file, and you will get two files. The text file is the licensed
file , and you import the Pacifico-Regular.ttf file into your Flutter project.
5-65
Flutter ™ Application Development
5- Open Your Android Studio, right click your project name, and then select:
New → Directory
type Fonts for the directory name, and then click OK.
6- Copy your font file “ Pacifico-Regular.ttf” and paste it inside the Fonts folder. Click
OK to confirm the previous step as illustrated in the following figure:
7- Now, as you did before when you imported an image to your project, you must
declare the font file in the pubspec.yaml file. To do that, double click : pubspec.yaml
file , and then add the following configuration below flutter:
5-66
Flutter Widgets Fundamentals AFD-200
flutter:
fonts:
- family: Pacifico
fonts:
- asset: Fonts/Pacifico-Regular.ttf
For importance, keep your font configurations with the same arrangement as
illustrated in the following figure:
import 'package:flutter/material.dart';
void main() {
runApp(
MyApp(),
);
}
5-67
Flutter ™ Application Development
5-68
Flutter Widgets Fundamentals AFD-200
1- Open Android Studio, and select File → New → New Flutter Project
2- Enter the following:
Project Name: lab_05 , and then click Next
Company domain name : androidatc.com,and then click Finish
3- Your plan is to create an app interface including three Card widgets as illustrated
in the following figure:
This means, you want to start with the basic Flutter app elements such as Sacffold,
AppBar, and SafeArea widgets. Then, you will add a Column widget which will
include these three Card widgets.
5-69
Flutter ™ Application Development
import 'package:flutter/material.dart';
void main() {
runApp(
lab5(),
);
}
5- You need to use three images in your app. First, create a new directory called
Images to your project folders structure, and then configure your app pubspec.yaml
file to use this directory (Images) for images.
Right click the project name lab_05 , and then select New → Directory. Type Images
for the directory name, and then click OK as illustrated in the following figure:
5-70
Flutter Widgets Fundamentals AFD-200
6- Open pubspec.yaml , and at the flutter: section, add the following code as it is exactly
illustrated in the following figure , and be sure there are two spaces in the left margin:
7- Click Packages get at the top of the pubspec.yaml file of the code editor page of
Android Studio as illustrated in the following figure:
8- Now, open the Lab files folder on your computer, open Images → Lab5 . and paste
the three images stated below from Images\Lab5 in the Images folder in your app.
•• VegetablePZ.png
•• cheesePZ.png
•• Fries.png
You should have the following file structure for your app Images folder:
9- Now, add the first Card widget to your app as a child widget of the Column widget.
This Card widget will include Image and Text widgets in addition to properties of
5-71
Flutter ™ Application Development
import 'package:flutter/material.dart';
void main() {
runApp(lab5(),);}
body: SafeArea(
child: Column(children: <Widget>[
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15)),
margin: EdgeInsets.all(10.0),
color: Colors.deepOrangeAccent,
elevation: 20.0,
child: Row(
children: <Widget>[
Image(
image: AssetImage('Images/VegetablePZ.png'),
width: 100.0,
height: 100.0,),
SizedBox(width: 20.0),
Text('Vegetable Pizza',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 30.0),
),
],
),
),
]),
),
5-72
Flutter Widgets Fundamentals AFD-200
),
);
}
}
10- Run your app now. You should get the following app interface:
11- Now , add the other two Card widgets as children widgets of the main Column
widget. You can Copy only previous Card widget code (between Card and //Card), and
then paste it twice, to get two more Card widgets as illustrated in the following code:
import 'package:flutter/material.dart';
void main() {
runApp(lab5(),);
}
backgroundColor: Colors.white,
body: SafeArea(
child: Column(children: <Widget>[
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15)),
margin: EdgeInsets.all(10.0),
color: Colors.deepOrangeAccent,
elevation: 20.0,
5-73
Flutter ™ Application Development
child: Row(
children: <Widget>[
Image(image: AssetImage('Images/VegetablePZ.png'),
width: 100.0,
height: 100.0,),
SizedBox(width: 20.0),
Text('Vegetable Pizza',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 30.0),
),
],
),
),
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15)),
margin: EdgeInsets.all(10.0),
color: Colors.deepOrangeAccent,
elevation: 20.0,
child: Row(
children: <Widget>[
Image(image: AssetImage('Images/VegetablePZ.png'),
width: 100.0,
height: 100.0,),
SizedBox(width: 20.0),
Text('Vegetable Pizza',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 30.0),
),
],
),
),
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15)),
margin: EdgeInsets.all(10.0),
color: Colors.deepOrangeAccent,
elevation: 20.0,
5-74
Flutter Widgets Fundamentals AFD-200
child: Row(
children: <Widget>[
Image(image: AssetImage('Images/VegetablePZ.png'),
width: 100.0,
height: 100.0,),
SizedBox(width: 20.0),
Text('Vegetable Pizza',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 30.0),
),
],
),
),
]),
),
),
);
}
}
12- Click the Hot Reload button, then you will get the following app interface.
13- In the code of the second Card widget, replace the Image VegetablePZ.png with
cheesePZ.png , and the Text value: Vegetable Pizza with Cheese Pizza
5-75
Flutter ™ Application Development
14- In the code of the third Card widget, replace the Image VegetablePZ.png with
Fries.png , and the Text value: Vegetable Pizza with Box of Fries
15 - Click the Hot Reload button. You should get the following output run result:
Congratulations !
This is the first app interface you have created. In the next lessons, you will learn
how to add amazing features to your app.
These lab source code files are available in the Lab Source Files folder
on your computer. If you don’t have these lab files, please contact us at
[email protected]
5-76
Navigation and Routing AFD-200
6-1
Flutter ™ Application Development
Button Widget
In Flutter development, you may use the following types of buttons in your app design:
•• FloatingActionButton
•• RaisedButton
•• FlatButton
•• IconButton
•• ButtonBar
•• DropdownButton
•• OutlineButton
•• PopupMenuButton
FloatingActionButton Widget
A floating action button is by default a circular icon button that hovers over content
to promote a primary action in the application. Use at most a single floating action
button per screen. Floating action buttons should be used for positive actions such
as “create”, “share”, or “navigate”.
Now, you will create a new empty Flutter app, and then create a simple Flutter app
and test the code for which will build each type of the previous buttons.
4- Type : buttons_06 for Project Name and create a new folder : Lesson_06_Buttons
for Project Location. Click Next.
5- Type : androidatc.com for Company domain, and then click Finish
6- Open main.dart file ( lesson_06 → lib → main.dart).
7- Delete all the code contents in main.dart file.
6-2
Navigation and Routing AFD-200
8- Type the flowing code which will create a simple Flutter app. You will use this
code later in the next steps to test all types of buttons.
import 'package:flutter/material.dart';
main() {
runApp(
MyApp(),
);
}
body: SafeArea(
child: Column(
children: <Widget>[
Center(
child: SafeArea(
child: Text(
"Welcome to Android ATC",
style: TextStyle(
fontWeight: FontWeight.normal,
color: Colors.black,
fontSize: 25.0),
),
),
),
],
),
),
),
);
}
}
6-3
Flutter ™ Application Development
9- Run Your app. You should get the following run output:
10- Add the following code to add a FloatingActionButton in the Scaffold widget
as illustrated in the grey highlighted part of the following code:
import 'package:flutter/material.dart';
main() {
runApp(
MyApp(),
);
}
body: SafeArea(
child: Column(
children: <Widget>[
Center(
child: SafeArea(
child: Text(
"Welcome to Android ATC",
style: TextStyle(
fontWeight: FontWeight.normal,
color: Colors.black,
fontSize: 25.0),
),
),
6-4
Navigation and Routing AFD-200
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.phone),
),
),
);
}
}
Between the two braces of onPressed: (){} function, you can add the action
which will be taken if the app user taps this button as you will see in the navigation
section in this lesson.
Also, you may replace the phone in Icon(Icons.phone) with another icon name
such as share , favorite, or other types of icons.
The run output of this app follows:
6-5
Flutter ™ Application Development
Continue using the same Flutter project buttons_06, and add these three buttons as
illustrated in the following code:
import 'package:flutter/material.dart';
main() {
runApp(MyApp(),
);
}
// Raised Button
RaisedButton(
color: Colors.blue,
child: Text(
'Raised Button',
style: TextStyle(
6-6
Navigation and Routing AFD-200
fontWeight: FontWeight.normal,
color: Colors.white,
fontSize: 20.0),
),
onPressed: () {},
),
// Icon Button
IconButton(
icon: Icon(Icons.volume_up),
tooltip: 'Increase volume by 10',
onPressed: () {},
),
Text('Sound'),
// Flat Button
FlatButton(
color: Colors.blue,
textColor: Colors.white,
disabledColor: Colors.grey,
disabledTextColor: Colors.black,
padding: EdgeInsets.all(8.0),
splashColor: Colors.blueAccent,
onPressed: () {},
child: Text(
"Flat Button",
style: TextStyle(fontSize: 20.0),
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.favorite),
),
),
);
}
}
6-7
Flutter ™ Application Development
DropdownButton Widget
A drop down button widget is similar to a drop-down menu that allows your app
user to choose only one value from a list. It depends on other Dart methods in its
configuration as you will see in the next example.
Example:
In this example, to create a drop down button: First, you should define the variable
which will have the value of the drop down list. In this example and as illustrated
in the following figure, you will use city as a list variable. Second, declare the
DropDownButton widget as a string data type because all items in this drop down
6-8
Navigation and Routing AFD-200
list are string. You will use items widget property to include all the items. Here, you
will configure the city variable as map, because this variable has many values, and
the map function will assign a key for each value. Also, use ".toList()" method
to add all variable values of this stream to the list in the order they arrive.
The block of code includes DropdownMenuItem widget which will return a value to
the list if the user selects a menu item as illustrated in the following code:
DropdownButton<String>(
Now, you will add setState() function which will notify your app framework that
the selected drop down item (variable value) of this list has been changed. This
function works through onChanged property. onChanged property (Listener) will run
setState() function every time the value in the drop down list changes.
6-9
Flutter ™ Application Development
DropdownButton<String>(
items:city.map((String dropDownStringItem){
return DropdownMenuItem<String>(
value: dropDownStringItem,
child: Text(dropDownStringItem),
);
}).toList(),
onChanged: (){
setState({ Your Code });
// Here your code will execute when the user select a new item.
},
);
);
Continue using the previous Flutter project and perform the following steps:
2- After the end of the last button FlatButton , add the DropdownButton widget code.
import 'package:flutter/material.dart';
main() {
runApp(
6-10
Navigation and Routing AFD-200
MyApp(),
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Lesson 06: Buttons'),
),
body: SafeArea(
child: Column(children: <Widget>[
Center(
child: SafeArea(
child: Text(
"Welcome to Android ATC",
style: TextStyle(
fontWeight: FontWeight.normal,
color: Colors.black,
fontSize: 25.0),
),
),
),
// Raised Button
RaisedButton(
color: Colors.blue,
child: Text(
'Raised Button',
style: TextStyle(
fontWeight: FontWeight.normal,
color: Colors.white,
fontSize: 20.0),
6-11
Flutter ™ Application Development
),
onPressed: () {},
),
// Icon Button
IconButton(
icon: Icon(Icons.volume_up),
tooltip: 'Increase volume by 10',
onPressed: () {},
),
Text('Sound'),
// Flat Button
FlatButton(
color: Colors.blue,
textColor: Colors.white,
disabledColor: Colors.grey,
disabledTextColor: Colors.black,
padding: EdgeInsets.all(8.0),
splashColor: Colors.blueAccent,
onPressed: () {},
child: Text(
"Flat Button",
style: TextStyle(fontSize: 20.0),
),
),
DropdownButton<String>(
items: city.map((String dropDownStringItem) {
return DropdownMenuItem<String>(
value: dropDownStringItem,
child: Text(dropDownStringItem),
);
}).toList(),
onChanged: (String NewUserValue) {
setState(() {
this.firstcity = NewUserValue;
});
},
value: firstcity,
// Here, firstcity variable value is Toronto.
// value:firstcity means, the default city value which will
// appear to the app user.
6-12
Navigation and Routing AFD-200
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.favorite),
),
),
);
}
}
OutlineButton Widget
OutlineButton is similar to a FlatButton with a thin grey rounded border.
Perform the following steps to add an outline button to your app interface:
1- Continue using the pervious code for Flutter project buttons_06 , and add the
OutlineButton as a child widget of the Column widget as illustrated in the grey
highlighted part of the following code:
import 'package:flutter/material.dart';
main() {
runApp(
MyApp(),
);
}
6-13
Flutter ™ Application Development
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Lesson 06: Buttons'),
),
body: SafeArea(
child: Column(children: <Widget>[
OutlineButton(
),
OutlineButton(
shape: StadiumBorder(),
highlightedBorderColor: Colors.blue,
child: Text('Outline Button'),
onPressed: () {},
),
3- Run your app. When you tap this button, you will find a type of change in color
in the button background. It is similar to Adobe Flash buttons because it creates a
type of interactivity with the app user.
ButtonBar Widget
This widget is a horizontal arrangement of other types of buttons. For example,
this widget can include three or four of flat or outline buttons and arrange them
horizontally to appear as a horizontal navigation bar for your app.
These buttons are children widgets for the ButtonBar widget , and it is a good idea
to use the alignment property with value : MainAxisAlignment.center which
places other children buttons as close to the middle of the main axis as possible.
The following example displays how to configure the ButtonBar widget to include
other three OutlineButton widgets.
1- Continue using the previous code of project buttons_06 , and add the ButtonBar
6-14
Navigation and Routing AFD-200
widget as the first widget to the Column widgets as illustrated in the grey
highlighted part of the following code:
body: SafeArea(
child: Column(children: <Widget>[
ButtonBar(
2- Add three OutlineButton as children widgets for your ButtonBar widgets. Only
change the Text widget values for these children buttons to have : Flights, Hotels,
and Cars . Also, use alignment: MainAxisAlignment.center property to place
these buttons as close to the middle of the main axis as possible.
The code follows:
body: SafeArea(
child: Column(children: <Widget>[
ButtonBar(
alignment: MainAxisAlignment.center,
children: [
OutlineButton(
shape: StadiumBorder(),
highlightedBorderColor: Colors.blue,
child: Text('Flights'),
onPressed: () {},
6-15
Flutter ™ Application Development
),
OutlineButton(
shape: StadiumBorder(),
highlightedBorderColor: Colors.blue,
child: Text('Hotels'),
onPressed: () {},
),
OutlineButton(
shape: StadiumBorder(),
highlightedBorderColor: Colors.blue,
child: Text('Cars'),
onPressed: () {},
),
],
),
6-16
Navigation and Routing AFD-200
PopupMenuButton Widget
This button can be created at any place in the app. When the app user taps on this
button, it displays a menu with many items, and calls onSelected property which
includes an action for each menu item as you will see in the next example.
The following figure displays how the PopupMenuButton widget appears at the app
bar for Android and iOS phones:
Example:
Here, you will create a new Flutter app to focus more on configuring the
PopupMenuButton widget and its properties. To create a new Flutter app and
configure the PopupMenuButton widget, perform the following steps:
6-17
Flutter ™ Application Development
import 'package:flutter/material.dart';
main() {
runApp(
MyApp(),
);
}
actions: <Widget>[
PopupMenuButton(
onSelected: choiceAction,
itemBuilder: (BuildContext context) {
return item.choices.map((choice) {
return PopupMenuItem(
value: choice,
child: Text(choice),
);
}).toList();
},
)
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Welcome to Android ATC',),
],
),
6-18
Navigation and Routing AFD-200
),
),
);
}
void choiceAction(choice) {
if (choice == item.Inbox) {
print('Inbox');
}
}
}
class item {
static const Inbox = 'Inbox';
static const SentItems = 'Sent Items';
static const JunckEmail = 'Junck E-mail';
static const SignOut = 'Sign Out';
9- Run your app and you should get the following run output:
6-19
Flutter ™ Application Development
10- Click the Popup Menu Button which exits on your app title bar.
11- The grey highlighted parts of the previous code display the action which will
be done when you select any of the popup menu items. In this example , when you
select Inbox , the app will print Inbox on the run console. The same thing applies for
other items as illustrated in the following figure:
6-20
Navigation and Routing AFD-200
In your app, you will use various navigation techniques to move from one screen to
another. For any app to be successful, it should be easy to use and have a variety
of navigation techniques. This would help app users to reach and use app data in a
simple and easy manner, using friendly app interfaces
Therefore, try to make your app user friendly, and design it to meet the needs of app
users and businesses in more than one way.
In this lesson, you will learn almost all these navigation methods using different
types of navigation techniques.
6-21
Flutter ™ Application Development
or “pages”. In Flutter, these elements are called routes and they are managed by
a Navigator class or widget. Flutter navigator takes you on each of these routes to
see each of these screens.
The Navigator class manages a stack of Route (screen) objects and provides
methods for managing the stack, like Navigator.push and Navigator.pop.
In this example, you will create a Flutter app including main.dart file and other 3 Dart
files (screen0.dart, screen1.dart, and screen2.dart).
You will use the navigator class to move from Screen 0 (main.dart) to Screen 1
(screen1.dart) , and return form Screen 1 (screen1.dart) to Screen 0 (main.dart) .
Perform the following steps:
1- Open Android Studio
2- Click File → New → New Flutter Project
3- Select Flutter Application , and then click Next.
4- Type : lesson_06 for Project Name , and create a new folder :D:\Lesson_06 for
Project Location. Click Next.
5- Type : androidatc.com for Company domain, and then click Finish
6- Now, create screen0.dart (Screen 0 interface). Right click lib folder , select New → Dart File
7- Type the name of the file : screen0 , and then press Enter as illustrated in the
following figure:
8- Repeat the previous task to create the screen1.dart, and screen2.dart files.
9- Open screen1.dart , and type the following code:
import 'package:flutter/material.dart';
6-22
Navigation and Routing AFD-200
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
title: Text('Screen 1'),
),
body: Center(
),
);
}
}
10- Now, you will add a button on interface 0 (screen0.dart) , and when you tap this
button you will go to Screen 1 (screen1.dart).
The following figure displays where you must add the navigator class in the button:
You will add Navigator.push method inside the onPressed method body.
This push() method adds a Route to the stack of routes (interfaces) managed
by the Navigator. The following figure displays the Navigator.push method
parameters :
6-23
Flutter ™ Application Development
When you run the Navigator.push()method on screen 0 (main.dart), you push out
this screen and then another screen appears on the smart device depending on this
method configuration.
import 'package:flutter/material.dart';
import 'screen1.dart';
body: Center(
6-24
Navigation and Routing AFD-200
child: Column(
children: <Widget>[
RaisedButton(
color: Colors.blue,
child: Text('Go To Screen 1'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return Screen1();
}),
);
},
),
],
),
));
}
}
The grey highlighted part of the previous code is related to the Raised Button. The
navigator class in the OnPressed()method is responsible to configure the route
which you will use to move from Screen 0 to Screen 1 when you tap this button.
You must import the screen1.dart as you did on the second line of the above code
to define Screen1( ) in screen0.dart.
11- Open main.dart file, and delete all its content. Then type the following code:
import 'package:flutter/material.dart';
import 'screen0.dart';
main() {
runApp(
MyApp(),
);
}
6-25
Flutter ™ Application Development
return MaterialApp(
home: Screen0(),
);
}
}
Now, when you run your app, the main.dart file will run screen0.dart file due to the
grey highlighted part of main.dart file.
12- Run your app. You will get the following figure. Tap this button, and then you will
go to Screen 1.
13- Open screen1.dart, copy all the code, open screen2.dart, and then paste the code.
14- Just change the class name to Screen 2. Then change the Scaffold title to
Screen 2. You should have the following code in screen2.dart :
import 'package:flutter/material.dart';
body: Center(),
);
}
}
6-26
Navigation and Routing AFD-200
15- Open Screen 1 (screen1.dart), and add a new button that has a route to Screen 2
as illustrated in the following code:
import 'package:flutter/material.dart';
import 'screen2.dart';
body: Center(
child: Column(
children: <Widget>[
RaisedButton(
color: Colors.green,
child: Text('Go To Screen 2'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return Screen2();
}),
);
},
),
],
)),
);
}
}
16- Run your app. Tap the button “Go To Screen 1” , and then tap the button “Go To
Screen 2” you will go to Screen 2.
6-27
Flutter ™ Application Development
onPressed: () {
Navigator.pop(context);
}
17- Open Screen 2 (screen2.dart) and add a button that has a return to original route
using Navigator.pop() method. When you tap this button, you return to Screen 1
(screen1.dart).
The code follows:
import 'package:flutter/material.dart';
body: Center(
child: Column(
children: <Widget>[
RaisedButton(
color: Colors.green,
child: Text('Return'),
onPressed: () {
Navigator.pop(context);
},
),
],
),
6-28
Navigation and Routing AFD-200
),
);
}
}
Run your app again. Tap the button “Go To Screen 1” , and then tap the button “Go
To Screen 2”. On Screen 2 , when you tap Return button , you will return to Screen 1
as illustrated in the following figures:
You will use Dart map technique to assign a name (key) to each route. The map
object has already been explained with examples in lesson 2 of this course.
Remember that DART map is an object that associates keys to values. In DART,
map is an interface designed to manipulate a collection of keys which point to
values (routes).
Continue using the previous project (lesson_06) which includes four Dart files, and
perform the following steps:
2- Type homepage for the file name, and then press Enter as illustrated in the
6-29
Flutter ™ Application Development
following figure.
3- Open homepage.dart file and type the following code to create three navigation buttons:
import 'package:flutter/material.dart';
body: Center(
child: Column(
children: <Widget>[
RaisedButton(
color: Colors.green,
child: Text('Go To Screen 0'),
onPressed: () {}),
RaisedButton(
color: Colors.green,
child: Text('Go To Screen 1'),
onPressed: () {}),
RaisedButton(
color: Colors.green,
child: Text('Go To Screen 2'),
onPressed: () {}),
],
),
),
);
}
}
6-30
Navigation and Routing AFD-200
4- If you want to make the hompepage.dart as the startup page when you run your
app. you would need to open main.dart file and then add the following command at
the beginning of this file:
import 'homepage.dart';
Now, replace the home value with HomePage() as illustrated in the grey highlighted
color in the main.dart file as follows:
import 'package:flutter/material.dart';
import 'homepage.dart';
import 'screen0.dart';
main() {
runApp(
MyApp(),
);
}
home: HomePage(),
);
}
}
5- Run your app. You should get the following run output:
6-31
Flutter ™ Application Development
6- Now, you should add a navigation map including keys to all routes. Open main.
dart file, and then add your app map of routes as illustrated in the following code:
import 'package:flutter/material.dart';
import 'homepage.dart';
import 'screen0.dart';
import 'screen1.dart';
import 'screen2.dart';
main() {
runApp(
MyApp(),
);
}
routes: {
'0': (context) => Screen0(),
'1': (context) => Screen1(),
'2': (context) => Screen2(),
},
);
}
}
The following figure displays the map structure where each key represents a
navigation route.
6-32
Navigation and Routing AFD-200
import 'package:flutter/material.dart';
RaisedButton(
color: Colors.green,
child: Text('Go To Screen 0'),
onPressed: () {
Navigator.pushNamed(context, '0');
}),
RaisedButton(
color: Colors.green,
child: Text('Go To Screen 1'),
onPressed: () {
Navigator.pushNamed(context, '1');
}),
RaisedButton(
color: Colors.green,
child: Text('Go To Screen 2'),
onPressed: () {
Navigator.pushNamed(context, '2');
}),
],
),
),
);
}
}
6-33
Flutter ™ Application Development
8- Now, Run your app, and test the three buttons on homepage.dart. You will find
that you can move to all routes easily.
Note: Use the back arrow button to return to the previous interface.
2- Declare and add a string variable FirstName to Screen2 class. Also, change your
appBar title value to use this FirstName variable as illustrated in the following gray
highlighted code:
import 'package:flutter/material.dart';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
title: Text(FirstName),
),
body: Center(
child: Column(
children: <Widget>[
RaisedButton(
color: Colors.green,
child: Text('Return'),
6-34
Navigation and Routing AFD-200
onPressed: () {
Navigator.pop(context);
},
),
],
),
),
);
}
}
3- Open screen1.dart , and configure the value of FirstName variable with the return
function in the raised button as illustrated in the following figure:
Replace “Your First Name” with your real first name in the above code , then save
and run your app.
4- Tap “Go To Screen 1” button, and then tap “Go to Screen 2” button. You will get
the following figure:
6-35
Flutter ™ Application Development
Use the Hero widget to animate a widget from one screen to the next. This recipe
uses the following steps:
6-36
Navigation and Routing AFD-200
Here, second.dart file will be the destination file. This means when the app user
taps the image in the main.dart file (first interface) , the app will open second.dart
file (next interface) which includes the same image with a bigger size. This action
produces an animation effect done while navigating between screens.
9- As you did before in lesson 5 in the adding asset image topic, configure the
default location of the asset images folder in the pubspec.yaml file.
Remember, the part which is related to add an asset image in pubspec.yaml file
must be configured as the follows:
6-37
Flutter ™ Application Development
10- Open the “Lab Source Files → images “ folder on your computer , and then copy
the pizza.png image and paste it in the Images folder in your Flutter app. You will
get the following figure. Click OK.
11- Open second.dart and add the code below. Here, the GestureDetector class
defers the image for its sizing behavior, and the Hero widget will implement a
style of animation between second.dart and main.dart .This Hero widget uses
tag:'imageHero' as a widget property to perform an image animation between the
app screens.
import 'package:flutter/material.dart';
body: GestureDetector(
child: Center(
child: Hero(
tag: 'imageHero',
child: Image(
image: AssetImage('Images/pizza.png'),
width: 400.0,
height: 400.0,
),
),
6-38
Navigation and Routing AFD-200
),
onTap: () {
Navigator.pop(context);
},
),
);
}
}
import 'package:flutter/material.dart';
import 'second.dart';
main() {
runApp(
MyApp(),
);
}
body: GestureDetector(
child: Hero(
tag: 'imageHero',
child: Image(
6-39
Flutter ™ Application Development
image: AssetImage('Images/pizza.png'),
width: 120.0,
height: 120.0,
),
),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (_) {
return Second();
} ),);
},
),
);
}
}
14- Run your app, and then click the pizza image on your app interface. You will
move to the second.dart . Flying the pizza image from the first screen to another is
called a hero animation in Flutter.
Remember, the Hero widget animates from the source to the destination route.
WebView in Flutter
You can embed a web browser inside your app using WebView widget. A WebView
widget is a crucial component for many apps that need to display website
content without worrying about using Android or iOS native views. Incorporating
the WebView plug-in into your app is extremely simple. WebView widget is just
like any other widget in Flutter. For example, you can add the following WebView
widget to display Android ATC web site content in your app interface. By default,
JavaScript in your WebView widget is disabled, so to enable it, you should add the
javascriptMode property with unrestricted value to your WebView widget as
illustrated in the code below:
WebView(
initialUrl: 'https://www.androidatc.com',
javascriptMode: JavascriptMode.unrestricted,)
6-40
Navigation and Routing AFD-200
Example:
1- Open Android Studio
2- Click File → New → New Flutter Project
3- Select Flutter Application , and then click Next.
4- Type : webview_06 for Project Name , and create a new folder : Web_View_06 for
Project Location. Click Next.
5- Type : androidatc.com for Company domain, and then click Finish
6- Open main.dart (webview_06 → lib → main.dart).
7- Add the webview_flutter plug-in to your app pubspec.yaml file. The following
figure displays the pubspec.yaml file location and the webview_flutter plug-in
configuration.
<key>io.flutter.embedded_views_preview</key>
<string>YES</string>
Add these two lines to Info.plist file as illustrated in the following figure:
6-41
Flutter ™ Application Development
import 'package:flutter/material.dart';
main() {
runApp(
MyApp(),
);
}
11- Double click the WebView widget, click the red lamp icon, and then select:
6-42
Navigation and Routing AFD-200
following figure:
12- Now, add the URL for the destination web site. For example https://www.google.
com. The full code will be as follows:
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
main() {
runApp(
MyApp(),
);
}
13- Run your app. The run output for Android and iOS follows:
6-43
Flutter ™ Application Development
6-44
Navigation and Routing AFD-200
The twitter image will open a twitter web site on a new interface within the app
using the WebView widget. Also, the Facebook image will open a new interface
including the Facebook web site.
Before starting, just check the following app interfaces which represent the app
interfaces you will create in this lab.
6-45
Flutter ™ Application Development
6-46
Navigation and Routing AFD-200
As you see, each interface has the same title bar, Facebook logo, twitter logo, and
other three navigation buttons. Therefore, you will design one interface including all
these common widgets in a file called home.dart first. Then, use the copy and paste
technique to repeat the same code for all other dart files (other app interfaces).
The ButtonBar widget which represents the navigation buttons, will be repeated
in home.dart, vpizaa.dart, chpizza.dart, and fries.dart files. In the early stage of
building the code, the facebook.dart and twitter.dart files will include the same
codes as other Dart files (app interfaces) excluding the three navigation buttons
(ButtonBar widget).
To create this app perform the following steps:
1- Open Android Studio
2- Click File → New → New Flutter Project
3- Select Flutter Application , and then click Next.
4- Type : lab_6 for Project Name , and create a new folder : Lab_06 for Project
Location. Click Next.
5- Type : androidatc.com for Company domain, and then click Finish
6- Create the Images folder which will include all your app images.
Right click the root project name (lab_6) → New → Directory . Type Images for the
directory name, and then click OK.
7- All your app images are available in the images folder (Images\Lab 6) in “Lab
Source Files”. Open this folder and then copy the images below:
cheesepizza.png, Vpizza.png, Fpizza.png, meal.jpg, twitter.png , and facebook.png
Then, paste them in the Images folder in Android Studio.
6-47
Flutter ™ Application Development
8- You will use the WebView widget plug-in to open the Facebook and Twitter web
sites in your app; therefore, you must configure the pubspec.yaml and info.plist files
to enable using the WebView widget in Android and iOS devices. Also, configure the
Images folder as the default location for all images.
a) Open the pubspec.yaml and add the webview_flutter: ^0.3.1 as illustrated in the
following figure:
Scroll down the pubspec.yaml and remove the comment sign for the assets and add
Images folder as illustrated in the following figure:
b) Open info.plist file (lab_6 → iso → Runner → Info.plist ), and then add the
following code to the Info.plist file <dict> element:
<key>io.flutter.embedded_views_preview</key>
<string>YES</string>
Add these two lines to Info.plist file as illustrated in the following figure:
6-48
Navigation and Routing AFD-200
import 'package:flutter/material.dart';
SizedBox)width: 160.0,(,
Image.asset)
'Images/twitter.png',
fit: BoxFit.contain,
height: 30,(,
SizedBox)width: 10.0,(,
Image.asset)
'Images/facebook.png',
fit: BoxFit.contain,
height: 40,(,
](,
(,
body: SafeArea)
child: Column)
children: <Widget>[
ButtonBar)
6-49
Flutter ™ Application Development
alignment: MainAxisAlignment.center,
children: [
OutlineButton(
shape: StadiumBorder(),
highlightedBorderColor: Colors.red,
child: Text('Vegetable Pizza',
style: TextStyle(fontSize: 20.0, color: Colors.orange),),
onPressed: () {
Navigator.pushNamed(context, '0');
},),
OutlineButton(
shape: StadiumBorder(),
highlightedBorderColor: Colors.red,
child: Text('Cheese Pizza',
style: TextStyle(fontSize: 20.0, color: Colors.orange),),
onPressed: () {
Navigator.pushNamed(context, '1');
},),
OutlineButton(
shape: StadiumBorder(),
highlightedBorderColor: Colors.red,
child: Text('Fries',
style: TextStyle(fontSize: 20.0, color: Colors.orange),),
onPressed: () {
Navigator.pushNamed(context, '2');
},),
],),
Center(
child: Column(children: [
Image.asset(
'Images/meal.jpg',
height: 300.0,
width: 400.0,),
Text(
"Hi, I'm the Pizza Assistant, what can I help you order?",
style: TextStyle(fontSize: 30.0),
textAlign: TextAlign.center,),
]),
6-50
Navigation and Routing AFD-200
),
],
),
),
),
);
}
}
11- Open main.dart ( lab_6 → lib → main.dart) and delete all its content.
12- The main.dart file will be configured to startup home.dart content when you run
this app, and it will include the navigation and named routes (keys) where you will
use the following named routes and keys:
Importance note: You will get a red underline for each class name in the routes map
because these classes are not created yet.
import 'package:flutter/material.dart';
import 'home.dart';
import 'chpizza.dart';
import 'facebook.dart';
import 'twitter.dart';
import 'vpizaa.dart';
import 'fries.dart';
main() {
runApp(
MyApp(),
6-51
Flutter ™ Application Development
import 'package:flutter/material.dart';
SizedBox)width: 160.0,(,
Image.asset)
'Images/twitter.png',
fit: BoxFit.contain,
height: 30,(,
SizedBox)width: 10.0,(,
6-52
Navigation and Routing AFD-200
Image.asset(
'Images/facebook.png',
fit: BoxFit.contain,
height: 40,),
],
),
),
body: SafeArea(
child: Column(
children: <Widget>[
ButtonBar(
alignment: MainAxisAlignment.center,
children: [
OutlineButton(
shape: StadiumBorder(),
highlightedBorderColor: Colors.red,
child: Text('Vegetable Pizza',
style: TextStyle(fontSize: 20.0, color: Colors.orange),),
onPressed: () {},
),
OutlineButton(
shape: StadiumBorder(),
highlightedBorderColor: Colors.red,
child: Text('Cheese Pizza',
style: TextStyle(fontSize: 20.0, color: Colors.orange),),
onPressed: () {},
),
OutlineButton(
shape: StadiumBorder(),
highlightedBorderColor: Colors.red,
child: Text('Fries',
style: TextStyle(fontSize: 20.0, color: Colors.orange),),
onPressed: () {},
),
],
),
Center(
child: Column(children: [
Image.asset(
6-53
Flutter ™ Application Development
'Images/meal.jpg',
height: 300.0,
width: 400.0,),
Text("Hi, I'm the Pizza Assistant, what can I help you order?",
style: TextStyle(fontSize: 30.0),
textAlign: TextAlign.center,
),
]),
),
],
),
),
),
);
}
}
14- To test your app so far, open main.dart file, and then change all the routes part to
comments by adding a double forward slash as illustrated in the following figure to
stop this temporary error:
6-54
Navigation and Routing AFD-200
15- Remove the comment signs again from main.dart. You may use Ctrl + / to add or
remove the double forward slash of any command.
16- Now, you want to add the navigation configuration to each onPressed:()
method in each button. To do that, add the grey highlighted part of the following
code to each button in home.dart file:
ButtonBar(
alignment: MainAxisAlignment.center,
children: [
OutlineButton(
shape: StadiumBorder(),
highlightedBorderColor: Colors.red,
child: Text('Vegetable Pizza',
style: TextStyle(fontSize: 20.0, color: Colors.orange),),
onPressed: () {
Navigator.pushNamed(context, '0');
},),
6-55
Flutter ™ Application Development
OutlineButton
shape: StadiumBorder ,
highlightedBorderColor: Colors.red,
child: Text 'Cheese Pizza',
style: TextStyle fontSize: 20.0, color: Colors.orange , ,
onPressed:
Navigator.pushNamed(context, '1');
, ,
OutlineButton
shape: StadiumBorder ,
highlightedBorderColor: Colors.red,
child: Text 'Fries',
style: TextStyle fontSize: 20.0, color: Colors.orange , ,
onPressed:
Navigator.pushNamed(context, '2');
,
,
],
,
17- Now , you will add a navigation route for the Facebook and twitter images. But
because these are images, you should add the GestureDetector()class to add the
navigation code. The following is the full code for the home.dart file :
import 'package:flutter/material.dart';
class Home extends StatelessWidget }
@override
Widget build)BuildContext context( }
return MaterialApp)
home: Scaffold)
appBar: AppBar)
backgroundColor: Colors.orange,
title: Row)
children: [
Text)'WOW Pizza',
style: TextStyle)fontSize: 20.0(,(,
SizedBox)width: 160.0,(,
Container)
child: GestureDetector)
onTap: )( }
6-56
Navigation and Routing AFD-200
Navigator.pushNamed(context, '3');
},
child: Image.asset(
'Images/twitter.png',
fit: BoxFit.contain,
height: 30,),),),
SizedBox(width: 10.0,),
Container(
child: GestureDetector(
onTap: () {
Navigator.pushNamed(context, '4');
},
child: Image.asset(
'Images/facebook.png',
fit: BoxFit.contain,
height: 40,),
),
),
],
),
),
body: SafeArea(
child: Column(
children: <Widget>[
ButtonBar(
alignment: MainAxisAlignment.center,
children: [
OutlineButton(
shape: StadiumBorder(),
highlightedBorderColor: Colors.red,
child: Text('Vegetable Pizza',
style: TextStyle(fontSize: 20.0, color: Colors.orange),),
onPressed: () {
Navigator.pushNamed(context, '0');
},),
OutlineButton(
shape: StadiumBorder(),
highlightedBorderColor: Colors.red,
child: Text('Cheese Pizza',
style: TextStyle(fontSize: 20.0, color: Colors.orange),),
onPressed: () {
Navigator.pushNamed(context, '1');
6-57
Flutter ™ Application Development
},),
OutlineButton(
shape: StadiumBorder(),
highlightedBorderColor: Colors.red,
child: Text('Fries',
style: TextStyle(fontSize: 20.0, color: Colors.orange),),
onPressed: () {
Navigator.pushNamed(context, '2');
},
),
],
),
Center(
child: Column(children: [
Image.asset(
'Images/meal.jpg',
height: 300.0,
width: 400.0, ),
Text("Hi, I'm the Pizza Assistant, what can I help you order?",
style: TextStyle(fontSize: 30.0),
textAlign: TextAlign.center,
),
]),
),
],
),
),
),
);
}
}
18- Copy all the lines of code in home.dart, and paste it in chpizza.dart, vpizza.dart,
fries.dart, facebook.dart, and twitter.dart.
19- Open chpizza.dart , and replace the class name Home in the first line with Chpizza
20- Open vpizza.dart, and replace the class name Home in the first line with Vpizaa
21- Open fries.dart, and replace the class name Home in the first line with Fries
22- Open facebook.dart, and replace the class name Home in the first line with Facebook
6-58
Navigation and Routing AFD-200
23- Open twitter.dart, and replace the class name Home in the first line with Twitter
24- Open vpizza.dart and scroll down at the last 6 lines and replace the meal.jpg
with Vpizza.png
27- Open facebook.dart. Remove only the content of the body widget. Then, add the
following code to the body widget:
WebView(
initialUrl: 'https://www.facebook.com',
javascriptMode: JavascriptMode.unrestricted),
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
SizedBox(width: 160.0,),
Container(
child: GestureDetector(
onTap: () {
Navigator.pushNamed(context, '3');
},
child: Image.asset(
'Images/twitter.png',
6-59
Flutter ™ Application Development
fit: BoxFit.contain,
height: 30,),),),
SizedBox(width: 10.0,),
Container(
child: GestureDetector(
onTap: () {
Navigator.pushNamed(context, '4');
},
child: Image.asset(
'Images/facebook.png',
fit: BoxFit.contain,
height: 40,
),
),
),
],
),
),
body: WebView(
initialUrl: 'https://www.facebook.com',
javascriptMode: JavascriptMode.unrestricted),
),
);
}
}
28-Double click the WebView widget, and click the red lamp icon as illustrated in the
following figure. Then, select:
Import library 'package:webview_flutter/webview_flutter.dart'.
6-60
Navigation and Routing AFD-200
29- Open the twitter.dart. Remove only the content of the body widget. Then, add the
following code to the body widget:
WebView
initialUrl: 'https://www.twitter.com',
javascriptMode: JavascriptMode.unrestricted ,
import 'package:flutter/material.dart';
SizedBox)width: 160.0,(,
Container)
child: GestureDetector)
onTap: )( }
Navigator.pushNamed)context, '3'(;
{,
child: Image.asset)
'Images/twitter.png',
fit: BoxFit.contain,
height: 30,
(,(,(,
SizedBox)width: 10.0,(,
Container)
child: GestureDetector)
onTap: )( }
Navigator.pushNamed)context, '4'(;
{,
6-61
Flutter ™ Application Development
child: Image.asset(
'Images/facebook.png',
fit: BoxFit.contain,
height: 40,
),
),
),
],
),
),
body: WebView(
initialUrl: 'https://www.twitter.com',
javascriptMode: JavascriptMode.unrestricted),
),
);
}
}
30-Double click the WebView widget , and click the red lamp icon. Then, select:
31- Run your app. Test the navigation buttons, Facebook, and twitter images.
Let us share with you the following ideas about this small Flutter project:
•• We should replace the Facebook and Twitter web sites with the Facebook and
Twitter links of this company (WoW Pizza Store Facebook and Twitter pages).
•• Beware that the main goal of apps is providing services directly to app users with
some interactivity such as notifications, offers, tracking system and others, rather
than giving details about the company history. Therefore, this app which you have
created still needs some other features such as placing an order, selecting the pizza
size and components , selecting delivery or pickup options , and selecting the nearest
branch to your location, depending on the GPS location on Google map.
These features will be discussed in the next lessons. Good luck !
6-62
Design Widgets - Part 1 AFD-200
Introduction............................................................................................................................ 7-2
BottomNavigatorBar Widget................................................................................................. 7-2
DefaultTabController, TabBar, and TabBarView Widgets..................................................... 7-5
ListTile Widget....................................................................................................................... 7-11
ListView Widget..................................................................................................................... 7-15
Drawer Widget........................................................................................................................ 7-18
DataTable Widget................................................................................................................... 7-29
SelectableText Widget........................................................................................................... 7-32
Stack Widget.......................................................................................................................... 7-35
Lab : 7..................................................................................................................................... 7-39
Lab A: Creating a Flutter App using BottomNavigatorBar Navigation Technique........ 7-40
Lab B: Using DataTable Sorting Built-in function............................................................ 7-45
7-1
Flutter ™ Application Development
Introduction
In this lesson, you will learn more about Flutter widgets especially those related
to navigating the app screens in different ways of navigations and configurations
techniques.
You may add more than one navigation method to your app that depends on your
app purpose and your customers’ targets. Remember, you should make your app as
easy to navigate and to find information as possible.
BottomNavigationBar Widget
Bottom navigation bar is a material widget that is displayed at the bottom of an app
for selecting among a small number of views, typically between three and five.
The bottom navigation bar consists of multiple items in the form of text labels,
icons, or both, laid out on top of a piece of material. It provides quick navigation
between the top-level views of an app.
Each item (icon) of this bar in the list has an index value. The first item from the
left side has 0 index value. You can configure each of these items to be the default
choice. It is quite bigger in size compared to other icons, and you can give it a
7-2
Design Widgets - Part 1 AFD-200
distinguished color. In the previous figure, it was white in color. You can configure
the default index by adding currentIndex property and value to the bottom
navigation bar. In the previous figure, the currentIndex:0; therefore, the default
selection was for the home icon.
Also, you can add many properties to the BottomNavigationBar such as icon
size to control the size of icons. However, the most important property is the type
property whose value should be BottomNavigationBarType.fixed, if you have
more than three items in this bottom navigation bar.
Example:
8- Type the following code which will create a simple Flutter app including bottom
navigation bar :
import 'package:flutter/material.dart';
main() {
runApp(
MyApp(),
);
}
7-3
Flutter ™ Application Development
),
body: Container(),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
fixedColor: Colors.white,
backgroundColor: Colors.blue,
iconSize: 30.0,
currentIndex: 0,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(Icons.access_alarm),
title: Text('Alarm'),
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
title: Text('Business'),
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
title: Text('School'),
),
],
),
),
);
}
}
7-4
Design Widgets - Part 1 AFD-200
Also, you may replace the fixedColor property with selectedItemColor and test
the effect of selectedFontSize and unselectedFontSize as illustrated in the
following code:
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
//fixedColor: Colors.white,
backgroundColor: Colors.blue,
selectedItemColor: Colors.white,
selectedFontSize: 19.0,
unselectedFontSize: 14.0,
iconSize: 30.0,
currentIndex: 0,
In the lab at the end of this lesson, you will learn how to configure the navigation
between app interfaces using the bottom navigation bar icons.
As illustrated in the below figure, to use tabs, you will first need a tab controller
(DefaultTabController) to keep the selected tab and the visible content in sync. The
easiest way to do this is using the DefaultTabController widget. Once you have that,
you will need a widget to show the tabs that the app user would use to switch between
the different interfaces of your app. This is where TabBar comes in. The TabBar takes a
list of tab widgets. You can have the tab show text, an icon, or a child widget.
7-5
Flutter ™ Application Development
In this example, you will create a new Flutter project that explains step by step how
to create an app using tab view technique to navigate the app contents.
4- Type : tabbar_tabbarview for Project Name, and Lesson_07 for Project Location. Click Next.
8- The following figure gives you an idea about the widgets which you will add to
the main.dart file and the role of each widget and property.
7-6
Design Widgets - Part 1 AFD-200
9- Type the following code in main.dart which will create a simple Flutter app
including tab navigation bar :
import 'package:flutter/material.dart';
body: DefaultTabController(
length: 3,
child: Column(
children: <Widget>[
Container(
child: TabBar(
labelColor: Colors.black,
unselectedLabelColor: Colors.blue,
indicatorColor: Colors.red,
labelStyle: TextStyle(
fontWeight: FontWeight.bold,
fontFamily: 'Arial',
fontSize: 20.0),
tabs: [
Tab(text: "Home"),
Tab(text: "Orders"),
Tab(text: "Login"),
]),
),
],
),
),
),
);
}
}
7-7
Flutter ™ Application Development
The following table includes the list of properties which you have already added to
the TabBar() widget in the previous code and the role of each:
Finally, you will need to create the content of each tab. This is where you use
TabBarView. Each widget in the list children corresponds to tabs in the TabBar widget.
There must be a one to one match between the tabs and the TabView children.
10- Create three Dart files to represent the content of each tab.
import 'package:flutter/material.dart';
child: Container(
child: Text('Home',
style: (TextStyle(fontSize: 30)),
)),
),
);
}
}
7-8
Design Widgets - Part 1 AFD-200
12- Copy all the content of screen1.dart, paste it in screen2.dart and in screen3.dart.
13- Open screen2.dart and replace the class name Screen1 with Screen2
14- Open screen3.dart and replace the class name Screen1 with Screen3
15- Open main.dart, and at the first line, add the following code to import screen1.
dart, screen2.dart, and screen3.dart to main.dart file:
import 'screen1.dart';
import 'screen2.dart';
import 'screen3.dart';
16- Now, you will use the TabBarView and TabView widgets to add the contents of
each tab as illustrated in the following code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'screen1.dart';
import 'screen2.dart';
import 'screen3.dart';
main() {
runApp(
MyApp(),
);
}
7-9
Flutter ™ Application Development
),
body: DefaultTabController(
length: 3,
child: Column(
children: <Widget>[
Container(
child: TabBar(
labelColor: Colors.black,
unselectedLabelColor: Colors.blue,
indicatorColor: Colors.red,
labelStyle: TextStyle(
fontWeight: FontWeight.bold,
fontFamily: 'Arial',
fontSize: 20.0),
tabs: [
Tab(text: "Home"),
Tab(text: "Orders"),
Tab(text: "Login"),
]),
),
Expanded(
child: Container(
child: TabBarView(
children: [
Container(
child: Screen1(),),
Container(
child: Screen2(),),
Container(
child: Screen3(),),
],
),
),
),
7-10
Design Widgets - Part 1 AFD-200
],
),
),
),
);
}
}
You may ask what is the Expanded widget which was used in the previous code?
Almost every Flutter layout uses rows and columns, and they are pretty cool. They
can hug their children tightly or spread them out and relax. But what if you would
like one of those children to stretch and fill the extra space? Just wrap it in an
Expanded widget and watch it grow.
17 - Run your app and test your app tabs. The following figure displays the app run output:
ListTile Widget
In some app layout designs, you have a list of items that you really want them to follow
the material design specifications. You could spend hours working out the perfect item
layout using rows, columns, containers, and various amounts of padding. Or, you could
just use a ListTile widget. ListTile widget implements the material design list spec
for you with full and easy control on its content. The following figure displays how the
ListTile widget looks like and some ListTile() widget properties:
7-11
Flutter ™ Application Development
Example:
In this example, you will create a new Flutter project that displays its contents using
ListTile() widget. Perform the following steps:
1- Open Android Studio
2- Click File → New → New Flutter Project
3- Select Flutter Application then click Next.
4- Type : list_tile_widget for Project Name and create a new folder : Lesson_07 for
Project Location. Click Next.
5- Type : androidatc.com for Company domain then click Finish
6- Open main.dart (list_tile_widget → lib → main.dart).
7- Delete all the code in main.dart .
8- Type the following code:
import 'package:flutter/material.dart';
7-12
Design Widgets - Part 1 AFD-200
body: Column(
children: <Widget>[
ListTile(
leading: Icon(Icons.phone),
title: Text('Main Title'),
subtitle: Text('This is my sub title'),
trailing: Icon(Icons.shopping_cart),
onTap: () => print('onTap Action'),
onLongPress: () => print('On Long Press Action'),
dense: false, // true means intensive content.
selected: true, // sets this tile as default.
enabled: true, // means that it can be tapped.
),
],
)),
);
}
}
9- Add additional ListTile widget to your app as illustrated in the following code:
import 'package:flutter/material.dart';
7-13
Flutter ™ Application Development
home: Scaffold(
appBar: AppBar(
title: Text('ListTile Widget'),
),
body: Column(
children: <Widget>[
ListTile(
leading: Icon(Icons.phone),
title: Text('Main Title'),
subtitle: Text('This is my sub title'),
trailing: Icon(Icons.shopping_cart),
onTap: () => print('onTap Action'),
onLongPress: () => print('On Long Press Action'),
dense: false,
selected: true,
enabled: true,
),
ListTile(
leading: Icon(Icons.school),
title: Text('Main Title'),
subtitle: Text('This is my sub title'),
trailing: Icon(Icons. share),
onTap: () => print('onTap Action'),
onLongPress: () => print('On Long Press Action'),
dense: false,
selected: true,
enabled: true,
),
],
)),
);
}
}
7-14
Design Widgets - Part 1 AFD-200
ListView Widget
If you want to set your app items to appear in a scrollable list, the ListView widget
is the perfect choice for your app layout. The default scroll direction of your app
items is vertical, however, you can change the scroll direction to horizontal. The
following code displays the main component of the ListView widget:
ListView(
children [item1, item2, item3],
);
Example:
In the following example, you will create a Flutter app including a simple ListView
widget having two ListTile widgets and one image as children items.
4- Type : list_view_widget for Project Name, and Lesson_07 for the Project Location. Click Next.
6- Right click the project main directory (list_view_widget), select New → Directory.
7-15
Flutter ™ Application Development
7- Configure the pubspec.yaml file to use the Images folder as a default location for
all images in this project as illustrated in the following figure:
8- From your Lab Source Code folder, open the images folder, copy the “sofa.jpg”
image, then paste it in Images folder in your app.
11- Type the following code in main.dart file. Note that you will add two ListTile
widgets which you have used in the previous section of this lesson as a ListView
item, as well as add “sofa.jpg” image as ListView widget item.
import 'package:flutter/material.dart';
body: ListView(
children: <Widget>[
ListTile(
leading: Icon(Icons.phone),
title: Text('Main Title'),
subtitle: Text('This is my sub title'),
trailing: Icon(Icons.shopping_cart),
onTap: () => print('onTap Action'),
7-16
Design Widgets - Part 1 AFD-200
),
ListTile(
leading: Icon(Icons.phone),
title: Text('Main Title'),
subtitle: Text('This is my sub title'),
trailing: Icon(Icons.shopping_cart),
onTap: () => print('onTap Action'),
selected: true,
),
Image(
image: AssetImage('Images/sofa.jpg'),
height: 300.0,
),
],
),
),
);
}
}
12- Run your app. You will get the following run output:
7-17
Flutter ™ Application Development
Try to copy these two ListTile widgets and paste them again as new item for
ListView widget. Repeat this step five times and run your app. Scroll down
(vertically) to see all your app content.
Drawer Widget
In apps that use Material Design, there are two primary options for navigation: tabs
and drawers. When there is insufficient space to support tabs, drawers provide a
handy alternative.
The following figure displays the Drawer widget components (navigation items):
7-18
Design Widgets - Part 1 AFD-200
In Flutter, use the Drawer widget in combination with a Scaffold to create a layout
with a Material Design drawer. This recipe uses the following steps:
a) Create a Scaffold.
b) Add a drawer.
c) Populate the drawer with items.
d) Close the drawer programmatically.
Example:
In this example, you will create a new Flutter project including a Drawer() widget
and add ListView navigation items .
7-19
Flutter ™ Application Development
4- Type : drawer_widget for Project Name and Lesson_07 for Project Location. Click Next.
6- In this app, you will create the main.dart file to include all navigation routes and
startup the home.dart file which will also include the app home interface and the
Drawer widget. This widget, as illustrated in the previous figure, will include a link to
other five pages (interfaces) as follows:
7- Add a new Dart file: home.dart (right click lib folder → New → Dart File). Open this
file and add the following code:
import 'package:flutter/material.dart';
body: Center(
child: Container(
child: Text('Welcome',
style: TextStyle(fontSize: 20.0),
),
7-20
Design Widgets - Part 1 AFD-200
),
),
),
);
}
}
Delete all the code in main.dart then type the following code:
import 'home.dart';
import 'package:flutter/material.dart';
9- Run your app. You will get an empty Drawer as illustrated in the following figure:
7-21
Flutter ™ Application Development
10- Open the home.dart file and add the ListView widget as a child widget of Drawer
widget. Also, add five ListTile widgets as children widgets of the ListView widget to
represent the Drawer items (Inbox, Sent Items, Profile, Settings, and Calendar). Let us
postpone the navigation routes configurations to the next step:
import 'package:flutter/material.dart';
drawer: Drawer(
child: ListView(children: <Widget>[
ListTile(
7-22
Design Widgets - Part 1 AFD-200
leading: Icon(Icons.mail,
color: Colors.blue,),
title: Text('Inbox',
style: TextStyle(color: Colors.blue, fontSize: 20.0),),
subtitle: Text('This is my sub title'),
trailing: Icon(Icons.arrow_right),
onTap: () => print('1'),
),
ListTile(
leading: Icon(Icons.send,
color: Colors.blue,),
title: Text('Sent Items',
style: TextStyle(color: Colors.blue, fontSize: 20.0),),
subtitle: Text('This is my sub title'),
trailing: Icon(Icons.arrow_right),
onTap: () => print('2'),
),
ListTile(
leading: Icon(Icons.person,
color: Colors.blue,),
title: Text('Profile',
style: TextStyle(color: Colors.blue, fontSize: 20.0),),
subtitle: Text('This is my sub title'),
trailing: Icon(Icons.arrow_right),
onTap: () => print('3'),
),
ListTile(
leading: Icon(Icons.settings,
color: Colors.blue,),
title: Text('Settngs',
style: TextStyle(color: Colors.blue, fontSize: 20.0),),
subtitle: Text('This is my sub title'),
trailing: Icon(Icons.arrow_right),
onTap: () => print('4'),
),
ListTile(
leading: Icon(Icons.calendar_today,
color: Colors.blue,),
title: Text('Calendar',
style: TextStyle(color: Colors.blue, fontSize: 20.0),),
subtitle: Text('This is my sub title'),
7-23
Flutter ™ Application Development
trailing: Icon(Icons.arrow_right,
color: Colors.blue,),
onTap: () => print('5'),
),
]),
),
body: Center(
child: Container(
child: Text('Welcome',
style: TextStyle(fontSize: 20.0),
),
),
),
),
);
}
}
11- Run your app and you will get the following run output:
7-24
Design Widgets - Part 1 AFD-200
12- Open home.dart file and use the DrawerHeader()widget to add a header to your
drawer items.
To control this drawer header height and other formats, add this DrawerHeader
widget as a child of the Container widget. You can do this easily by adding the
following gray highlighted part of the code to home.dart :
import 'package:flutter/material.dart';
drawer: Drawer(
child: ListView(children: <Widget>[
Container(
height: 35.0,
child: DrawerHeader(
margin: EdgeInsets.all(2.0),
padding: EdgeInsets.all(2.0),
child: Text(
'Android ATC Mail',
style: TextStyle(fontSize: 20.0, color: Colors.white),),
decoration: BoxDecoration(color: Colors.blue),
),
),
ListTile(
leading: Icon(Icons.mail,
color: Colors.blue,),
title: Text('Inbox',
style: TextStyle(color: Colors.blue, fontSize: 20.0),),
subtitle: Text('This is my sub title'),
trailing: Icon(Icons.arrow_right),
onTap: () => print('1'),
7-25
Flutter ™ Application Development
),
.....
.....
.....
13- Now, run your app and you should get the following run output:
15- Open main.dart file and add the navigation routes for the previous app interfaces
(mail_interface.dart, profile_interface.dart, and sent_items_interface.dart).
7-26
Design Widgets - Part 1 AFD-200
import 'home.dart';
import 'package:flutter/material.dart';
import 'mail_interface.dart';
import 'sent_items_interface.dart';
import 'profile_interface.dart';
home: Home(),
routes: {
'mail': (context) => Mail(),
'sentItem': (context) => SentItems(),
'profile': (context) => Profile(),
},
);
}
}
Important note: The names of the classes Mail() , SentItems(), and Profile()
are not created yet, therefore, you will get an error. After you create these classes,
everything will be fine.
16- Open home.dart file, and add a navigation route to each drawer item in the
ListTile widget as illustrated in the grey highlighted part of the home.dart
.....
.....
.....
ListTile(
leading: Icon(Icons.mail,
color: Colors.blue,),
title: Text('Inbox',
7-27
Flutter ™ Application Development
ListTile(
leading: Icon(Icons.send,
color: Colors.blue,),
title: Text('Sent Items',
style: TextStyle(color: Colors.blue, fontSize: 20.0),),
subtitle: Text('This is my sub title'),
trailing: Icon(Icons.arrow_right),
onTap: () => Navigator.pushNamed(context, 'sentItem'),
),
ListTile(
leading: Icon(Icons.person,
color: Colors.blue,),
title: Text('Profile',
style: TextStyle(color: Colors.blue, fontSize: 20.0),),
subtitle: Text('This is my sub title'),
trailing: Icon(Icons.arrow_right),
onTap: () => Navigator.pushNamed(context, 'profile'),
),
.....
.....
17- Copy all the contents of the home.dart file and paste them in the following Dart files:
18- Open the mail_interface.dart file, and complete the following tasks:
•• Replace the class name Home with Mail
•• Replace the AppBar title value : Drawer Widget with Mail Page
•• Replace the body widget Text value : Welcome with Mail Page
7-28
Design Widgets - Part 1 AFD-200
19- Open the sent_items_interface.dart file and complete the following tasks:
•• Replace the class name Home with SentItems
•• Replace the AppBar title value : Drawer Widget with Sent Items
•• Replace the body widget Text value : Welcome with Sent Items
20- Open the profile_interface.dart file, and complete the following tasks:
•• Replace the class name Home with Profile
•• Replace the AppBar title value : Drawer Widget with User Profile
•• Replace the body widget Text value : Welcome with User Profile
21- Run your app now and test your app navigation using your app drawer items.
DataTable Widget
Data tables display information in a grid-like format of rows and columns. They organize
information in a way that’s easy to scan so that users can look for patterns and insights.
The following figure displays the table which can be added to your app interface and
its components:
7-29
Flutter ™ Application Development
Example:
4- Type : data_table_widget for Project Name and use Lesson_07 for the Project
Location. Click Next.
6- Open main.dart file and delete all codes, then type the following code:
import 'package:flutter/material.dart';
7-30
Design Widgets - Part 1 AFD-200
body: Center(
child: Container(
child: DataTable(columns: [
DataColumn(label: Text('Car Make')),
DataColumn(label: Text('Model')),
DataColumn(label: Text('Price')),
], rows: [
DataRow(
cells: [
DataCell(Text('Honda')),
DataCell(Text('2010')),
DataCell(Text('5000')),
],
),
DataRow(
cells: [
DataCell(Text('Honda')),
DataCell(Text('2011')),
DataCell(Text('6000')),
],
),
DataRow(
cells: [
DataCell(Text('Honda')),
DataCell(Text('2012')),
DataCell(Text('7000')),
],
),
]),
),
)),
);
}
}
7-31
Flutter ™ Application Development
7- Run your app. You will get the following run output:
SelectableText Widget
This widget is important if you want to make your app text selectable. You may add this
widget to your app text content if you think that your app user may want to copy any
part of your app text to use it another app such as Google translator or Google search.
Example:
In this example, you will create a small and simple Flutter app including a
paragraph. Applying the SelectableText widget to these texts, your app users
can use text tools such as the copy option.
7-32
Design Widgets - Part 1 AFD-200
4- Type : selectable_text_widget for Project Name and Lesson_07 for the Project
Location. Click Next.
6- Open the main.dart file, delete all the file contents, then type the following code:
import 'package:flutter/material.dart';
body: SelectableText(
'These training courses have been developed and calibrated
by a team of Android experts for some years. These courses empower
application developers and IT-oriented employees with the skills to
build advanced Android applications. After completing these courses,
developer scan sit for online exams which entitle them to become
Certified Android Developers by Android ATC. Our exams are provided
through Pearson VUE authorized testing centers worldwide .',
style: TextStyle(fontSize: 20.0),
),
),
);
}
}
7-33
Flutter ™ Application Development
7- Run your app, select part of the run result and you will see the copy option as
illustrated in the following figure.
8- Also, you can add a cursor to your text when the app user taps on the app text.
This can be done by adding the grey highlighted part of code as properties to the
SelectableText widget as follows:
SelectableText(
'These training courses have been developed and calibrated by
a team of Android experts for some years. These courses empower
application developers and IT-oriented employees with the skills to
build advanced Android applications. After completing these courses,
developers can sit for online exams which entitle them to become
Certified Android Developers by Android ATC. Our exams are provided
through Pearson VUE authorized testing centers worldwide .',
style: TextStyle(fontSize: 20.0),
showCursor: true,
cursorColor: Colors.blue,
cursorWidth: 20,
),
7-34
Design Widgets - Part 1 AFD-200
9- Run your app again. You will realize that when you click on your app text, you will
get a blue flashing cursor.
Stack Widget
It is a widget that places its children widgets relative to the edges of its box. This
widget (class) is useful if you want to overlap several children widgets in a simple
way. Stack allows you to overlay multiple widgets on top of each other. These widgets
will appear like layers and you can control the position of these children widgets
using Positioned widget.
To know how Stake widget helps in organizing your interface content, check the
following example:
4- Type : stack_widget for Project Name and Lesson_07 for the project Location.
Click Next.
6- Open main.dart file, delete all codes and then type the following code:
import 'package:flutter/material.dart';
7-35
Flutter ™ Application Development
color: Colors.teal,
width: 100.0,
height: 100.0,
),
),
]),
),
);
}
}
7- You should know more about the Positioned widget and its properties (right, top,
bottom, and left). The following figure displays different positions of the previous
Container widget when you change the properties values of the Positioned widget.
7-36
Design Widgets - Part 1 AFD-200
8- The children widgets of Stack widgets work as layers when they are overlapped
in the position.
In the following code, you will add another Container widget which has a yellow color
and overlaps in its position with the previous Container widget. The code follows:
import 'package:flutter/material.dart';
7-37
Flutter ™ Application Development
9- Run your app and note that the last child Container widget (layer) overrides the
previous Container widget (layer) .
Positioned(
top: 210,
right: 160,
child: Container(
color: Colors.grey,
width: 50.0,
height: 50.0,
),
),
7-38
Design Widgets - Part 1 AFD-200
Lab 7:
This lab includes two projects as follows:
A. Create a Flutter App using BottomNavigatorBar Navigation
Technique
B. Using DataTable Sorting Built in function
7-39
Flutter ™ Application Development
7-40
Design Widgets - Part 1 AFD-200
import 'package:flutter/material.dart';
10- Open screen2.dart and type the following code (you can copy the content of
screen1.dart and paste it in screen2.dart, change the class name to Screen 2 and
change the Text widget value to Alarm):
import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
7-41
Flutter ™ Application Development
import 'package:flutter/material.dart';
13- Open main.dart file, delete all code, then type the following code:
import 'package:flutter/material.dart';
import 'screen1.dart';
import 'screen2.dart';
import 'screen3.dart';
import 'screen4.dart';
main() {
runApp(
MyApp(),
);
}
7-42
Design Widgets - Part 1 AFD-200
final tabs = [
Center(child: Screen1()),
Center(child: Screen2()),
Center(child: Screen3()),
Center(child: Screen4()),
];
int _currentindex = 0;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(' Bottom Navigation Bar '),
),
body: tabs[_currentindex],
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
backgroundColor: Colors.blue,
selectedItemColor: Colors.white,
selectedFontSize: 19.0,
unselectedFontSize: 14.0,
iconSize: 30.0,
currentIndex: _currentindex,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(Icons.access_alarm),
title: Text('Alarm'),
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
title: Text('Business'),
7-43
Flutter ™ Application Development
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
title: Text('School'),
),
],
onTap: (index) {
setState(() {
_currentindex = index;
});
},
),
),
);
}
}
14- Final step: Run your app and test your bottom navigation buttons.
7-44
Design Widgets - Part 1 AFD-200
4- Type : data_table_lab for Project Name and create a new folder : LAB_B_7 for
Project Location. Click Next.
6- Open main.dart file, delete all codes, then type the following code:
import 'package:flutter/material.dart';
body: Center(
child: Container(
child: DataTable(
columns: <DataColumn>[
7-45
Flutter ™ Application Development
DataColumn(
label: Text('Car Make'),
),
DataColumn(
label: Text("Model"),
),
DataColumn(
label: Text('Price'),
),
],
rows: <DataRow>[
DataRow(cells: [
DataCell(Text('Honda')),
DataCell(Text('2021')),
DataCell(Text('35000'))
])
],
),
),
),
),
);
}
}
7- Run your app. Here, you should get the following run output:
7-46
Design Widgets - Part 1 AFD-200
8- Now, you will change the table configuration to add the sort feature to the any
column in this table. Add the following properties to your DataTable widget
sortColumnIndex: 2,
sortAscending: false,
In your table, each column has an index number. The first column from the left side
has index value : 0, and the second column has index value : 1, and so on.
When you added sortColumnIndex: 2, to your TableData widget, this means that
you want to make the sorting based on the third column which is the price.
While the property sortAscending: false means the sorting type is descending (A → Z).
7-47
Flutter ™ Application Development
import 'package:flutter/material.dart';
body: Center(
child: Container(
child: DataTable(
sortColumnIndex: 2,
sortAscending: false,
columns: <DataColumn>[
DataColumn(
label: Text('Car Make'),
),
DataColumn(
label: Text("Model"),
),
DataColumn(
label: Text('Price'),
),
],
rows: <DataRow>[
7-48
Design Widgets - Part 1 AFD-200
DataRow(cells: [
DataCell(Text('Honda')),
DataCell(Text('2021')),
DataCell(Text('35000'))
]),
DataRow(cells: [
DataCell(Text('Toyota')),
DataCell(Text('2011')),
DataCell(Text('6000'))
]),
DataRow(cells: [
DataCell(Text('BMW')),
DataCell(Text('2010')),
DataCell(Text('9000'))
]),
],
),
),
),
),
);
}
}
10- Run your app again. If you tap the arrow symbol on the price column of your
table, you will NOT have any response, because the sorting process is designed to
move up or down all the row data which is related to the price column data.
To add a sorting feature to your table, you should make your table data dynamic. This
means that you should create a function that has a generation table data role. Then,
configure how this data should be arranged in the table cells depending on the sorting
option that will be taken whether ascending or descending, or if the sorting will be
applied to which column of the table. In other words, we can say that when the app user
clicks the sorting arrow, this app user will call the function which will generate the table
data to work and distribute this data in a specific way depending on the sorting method
7-49
Flutter ™ Application Development
11- Add the following code to create a Car class and carData variable which
represents the table data. Add the class and the variable at the end of your code
(after the last code bracket):
class Car {
String CarMake;
String Model;
double Price;
12- Now, if you want to apply sorting on the price column of this table, you should
add the following code to DataColumn widget for the price column as follows:
DataColumn(
label: Text('Price'),
numeric: false,
onSort: (i, b) {
setState(() {
carData.sort((a, b) => a.Price.compareTo(b.Price));
},
);
},
),
7-50
Design Widgets - Part 1 AFD-200
Explanation:
When you sort an array with .sort(), this assumes that you are sorting strings.
When sorting numbers, the default behavior will not sort them properly.
The function that you pass tells how to sort the elements. It takes two parameters
(a and b) that represents any two elements from the array (carData). The elements
will be sorted depending on the function’s return value a.Price.compareTo(b.
Price)); as follows:
The setState method notifies the framework that the internal state of this column
has changed in a way that might impact the user interface in this subtree, which
causes the framework to schedule a build for this State object.
13- It is a good idea to apply this sorting process to all other columns using the
same previous code with just the column name being changed. The full code until
this step is the following:
import 'package:flutter/material.dart';
7-51
Flutter ™ Application Development
body: Center(
child: Container(
child: DataTable(
sortColumnIndex: 2,
sortAscending: false,
columns: <DataColumn>[
DataColumn(
label: Text('Car Make'),
numeric: false,
onSort: (i, b) {
setState(() {
carData.sort((a, b) => a.CarMake.compareTo(b.CarMake));
},
);
},
),
DataColumn(
label: Text("Model"),
numeric: false,
onSort: (i, b) {
setState(() {
carData.sort((a, b) => a.Model.compareTo(b.Model));
},
);
},
),
DataColumn(
label: Text('Price'),
numeric: true,
onSort: (i, b) {
setState(() {
carData.sort((a, b) => a.Price.compareTo(b.Price));
},
);
},
),
],
7-52
Design Widgets - Part 1 AFD-200
rows: <DataRow>[
DataRow(cells: [
DataCell(Text('Honda')),
DataCell(Text('2021')),
DataCell(Text('35000'))
]),
DataRow(cells: [
DataCell(Text('Toyota')),
DataCell(Text('2011')),
DataCell(Text('6000'))
]),
DataRow(cells: [
DataCell(Text('BMW')),
DataCell(Text('2010')),
DataCell(Text('9000'))
]),
],
),
),
),
),
);
}
}
class Car {
String CarMake;
String Model;
double Price;
7-53
Flutter ™ Application Development
14- Now, working on configuring the table data, you don’t need to add this table data
manually. Remember, this table is a dynamic table. This means you should configure
the DataCell()class to represent the variables data table. These variables values
will be filled out from the carData list.
import 'package:flutter/material.dart';
body: Center(
child: Container(
child: DataTable(
sortColumnIndex: 2,
sortAscending: false,
columns: <DataColumn>[
DataColumn(
label: Text('Car Make'),
numeric: false,
onSort: (i, b) {
setState(() {
carData.sort((a, b) => a.CarMake.compareTo(b.CarMake));
},
);
7-54
Design Widgets - Part 1 AFD-200
},
),
DataColumn(
label: Text("Model"),
numeric: false,
onSort: (i, b) {
setState(() {
carData.sort((a, b) => a.Model.compareTo(b.Model));
},
);
},
),
DataColumn(
label: Text('Price'),
numeric: true,
onSort: (i, b) {
setState(() {
carData.sort((a, b) => a.Price.compareTo(b.Price));},
);
},
),
],
rows: carData
.map(
(x) => DataRow(
cells: [
DataCell(Text(x.CarMake)),
DataCell(Text(x.Model)),
DataCell(Text((x.Price).toString())),
],
),
).toList()),
),
),
),
);
}
}
class Car {
7-55
Flutter ™ Application Development
String CarMake;
String Model;
double Price;
15- Run your app and tap the arrow symbol. You will find that it works well as
illustrated in the following figure:
16- Replace the index value in sortColumnIndex:2 with 1, then run your app again. You will
get the sort arrow symbol added to the Model column. Test sorting for this column.
7-56
Widgets Design - Part 2 AFD-200
8-1
Flutter ™ Application Development
TextField widget is the most commonly used text input widget. By default,
a TextField is decorated with an underline. You can add a label, icon, and
inline hint text by supplying an InputDecoration as the decoration property of
the TextField.
Example:
As illustrated in the following figure, you will create a small Flutter app including
TextField widgets , and you will apply different properties for each TextField widget.
The above text fields are usually used in a form or in a login area of a Flutter app.
You should focus on the format of these fields ensuring that they will start at the
same left margin and set a space between the name of the field (such as Full
Name:) and the TextField which the user will use to enter his/her information.
It is a good idea to add your form fields inside a ListView widget and use its
property: shrinkWrap with value: true (shrinkWrap: true). This configuration
will guarantee that your app interface will display all your form contents and your
app user can easily scroll down to see all your app interface content.
Also, the best way to fully control designing the content of this form fields such as
the location of each field and the space between the field title and the field itself,
is to arrange each form line in a Row widget, each TextField inside a SizeBox
widget and add a SizeBox widget between the field title (such as Full Name:) and
the TextField widget to get a specific space. The following figure gives you an idea
about arranging form widgets using Row and SizeBox widgets.
8-2
Widgets Design - Part 2 AFD-200
4- Type: form_items for Project Name and create a new folder: Lesson_08 for
Project Location. Click Next
6- Open main.dart file, delete all the code, and type the following code:
import 'package:flutter/material.dart';
8-3
Flutter ™ Application Development
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Stack(
children: <Widget>[
ListView(
shrinkWrap: true,
children: <Widget>[
Text(
'Please enter the following information',
style: TextStyle(
fontSize: 22.0,
color: Colors.blue,
fontWeight: FontWeight.bold),
),
SizedBox(height: 10.0,),
Row(
children: [
Text('Full Name:',
style: TextStyle(fontSize: 20.0),),
SizedBox(width: 20.0,),
SizedBox(width: 220.0,
child: TextField(),
),
],
),
],
),
],
),
),
),
);
}
}
8-4
Widgets Design - Part 2 AFD-200
As you can see here in your app run output, the TextField has been represented by an
underline and its width is the width of the SizeBox widget which is its parent widget.
8- Before adding any property to the TextField widget, check first the following
table which includes almost of these widget properties:
Property Description
keyboardType: The device keys include only numbers. This means
TextInputType.number, the user can enter numbers only in this field.
After filling out the form information, the Enter or
textInputAction: Return button which will be used in your smart device
keys to send or submit this data will be Done for iOS
TextInputAction.done,
devices and check mark for Android devices. Also,
Instead of done you may use search or send.
maxLength: 25, You cannot type or enter more than 25 characters.
The characters in this field will appear as stars.
obscureText: true, This property is suitable if this field is assigned to
enter a password.
If this property value is true, the app user will get
autocorrect: true, suggestions when he/she start typing any data in
this field.
cursorColor: Colors.red, You can determine the cursor color .
8-5
Flutter ™ Application Development
InputDecoration Widget:
When you add this widget to the TextField widget, you can control the format of your
TextField widget. The following table includes properties you may add to this widget:
Property Description
By adding this property
to the InputDecoration
icon: Icon(Icons.email), widget you can add an
icon inside the typing
area of the TextField..
This configuration gives
hintText: 'Enter your name',
the app user a hint about
the format or data he/she
should enter.
When the input border
border: InputBorder.none, value is none, this will hide
the default underline for
the TextField widget.
focusedBorder: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(7.0)), This property will add a
borderSide: BorderSide(color: Colors.blue), radius border around the
), TextField widget.
9- Now, you will configure a form similar to the following figure by adding additional
TextField widgets and use the suitable properties for each TextField widget
depending on the data type (password, normal text, numbers, or etc.).
8-6
Widgets Design - Part 2 AFD-200
import 'package:flutter/material.dart';
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Stack(
children: <Widget>[
ListView(
shrinkWrap: true,
children: <Widget>[
Text('Please enter the following information',
style: TextStyle(
fontSize: 22.0,
color: Colors.blue,
fontWeight: FontWeight.bold),),
SizedBox(height: 10.0,),
Row(
children: [
Text('Full Name:',
style: TextStyle(fontSize: 20.0),),
SizedBox(width: 20.0,),
child: TextField(
maxLength: 25,
style: TextStyle(fontSize: 20, color: Colors.blue),
keyboardType: TextInputType.text,
textInputAction: TextInputAction.done,
autocorrect: true,
8-7
Flutter ™ Application Development
cursorColor: Colors.red,
decoration: InputDecoration(
hintText: 'Enter your name',
border: InputBorder.none,
focusedBorder: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(7.0)),
borderSide: BorderSide(color: Colors.blue),
),
),
),
)
],
),
SizedBox(height: 10.0,),
Row(
children: [
Text('Email Address:',
style: TextStyle(fontSize: 20.0),),
SizedBox(width: 20.0,),
SizedBox(width: 220.0,
child: TextField(
maxLength: 50,
style: TextStyle(fontSize: 20, color: Colors.blue),
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.done,
autocorrect: false,
cursorColor: Colors.red,
decoration: InputDecoration(
icon: Icon(Icons.email),
hintText: 'Your Email',
border: InputBorder.none,
focusedBorder: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(7.0)),
borderSide: BorderSide(color: Colors.blue),
),
),
),
8-8
Widgets Design - Part 2 AFD-200
),
],
),
SizedBox(height: 10.0,),
Row(
children: [
Text('Password:',
style: TextStyle(fontSize: 20.0),),
SizedBox(width: 20.0,),
SizedBox(width: 220.0,
child: TextField(
maxLength: 50,
obscureText: true,
style: TextStyle(fontSize: 20, color: Colors.blue),
textInputAction: TextInputAction.done,
autocorrect: false,
cursorColor: Colors.red,
decoration: InputDecoration(
border: InputBorder.none,
focusedBorder: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(7.0)),
borderSide: BorderSide(color: Colors.blue),
),
),
),
),
],
),
SizedBox(height: 10.0,),
Row(
children: [
Text('Telephone:',
style: TextStyle(fontSize: 20.0),),
8-9
Flutter ™ Application Development
SizedBox(width: 20.0,),
SizedBox(width: 220.0,
child: TextField(
maxLength: 12,
style: TextStyle(fontSize: 20, color: Colors.blue),
textInputAction: TextInputAction.done,
keyboardType: TextInputType.number,
autocorrect: false,
cursorColor: Colors.red,
decoration: InputDecoration(
border: InputBorder.none,
focusedBorder: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(7.0)),
borderSide: BorderSide(color: Colors.blue),
),
),
),
)
],
),
],
),
],
),
),
),
);
}
}
10- Run your app now and you will get the following run output:
8-10
Widgets Design - Part 2 AFD-200
You may repeat any of the previous TextField widgets many times in your code to
be sure that there is no problem in the scrolling process.
For example, the following code for a CheckboxGroup widget includes five check
boxes (5 labels):
8-11
Flutter ™ Application Development
CheckboxGroup(
labels: <String>[
"Onions",
"Mushrooms",
"Black olives",
"Green peppers",
"Extra cheese",
],),
RadioButtonGroup(
labels: <String>[
"One-Way Ticket",
"Round-Trip Ticket",
"Multi-City Ticket",
],),
Example:
In the following example, you will create a small Flutter app including
CheckboxGroup and RadioButtonGroup widgets.
grouped_buttons: ^1.0.4
8-12
Widgets Design - Part 2 AFD-200
7- Open main.dart file, delete all the code, and type the following code:
import 'package:flutter/material.dart';
import 'package:grouped_buttons/grouped_buttons.dart';
body: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 10.0,),
Text('Select Your Pizza Toppings :',
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
),
CheckboxGroup(
labelStyle: TextStyle(fontSize: 20.0),
abels: <String>[
"Onions",
"Mushrooms",
"Black olives",
8-13
Flutter ™ Application Development
"Green peppers",
"Extra cheese",
],
SizedBox(height: 10.0,),
RadioButtonGroup(
labelStyle: TextStyle(fontSize: 20.0),
labels: <String>[
"Small",
"Medium",
"Large",
],
),
],
),
),
),
);
}
}
7- Run your app and you should get the following result:
8-14
Widgets Design - Part 2 AFD-200
When you click your form items (check boxes and radio buttons), you will get the
following result on the run console:
8-15
Flutter ™ Application Development
The following table includes the properties which you may apply with the
CheckboxGroup or RadioButtonGroup widget:
Properties Description
checkColor The color to use for the check icon when a Checkbox is
checked (with CheckboxGroup only).
Specifies which boxes to be automatically checked. Every
element must match a label. This is useful for clearing all
checked selections (set it to [] ). If this is non-null, then the user
must handle updating this list, otherwise, the state of the
CheckboxGroup won’t change (with CheckboxGroup only).
Specifies which checkboxes or Radio buttons should be
disabled disabled. If this is non-null, no boxes will be disabled. The
strings passed to this must match the labels.
GroupedButtonsOrientation.VERTICAL.
8-16
Widgets Design - Part 2 AFD-200
Date Picker
In this topic, you will use the Date Picker plug-in to enter the date in your app
interface instead of asking the app user to enter it manually. Also, you will select
the date format (day, month and year).
Example:
In the following example, you will create a small Flutter app including all Date
Picker plug-in features to display and add the date to your app content. Your
design should be similar to the following figure:
8-17
Flutter ™ Application Development
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: MyApp()));
}
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(shrinkWrap: true, children: <Widget>[
Row(children: [
Text('Date Value',
style: TextStyle(fontSize: 20.0),
),
IconButton(
icon: Icon(Icons.date_range),
onPressed: () {},
),
]),
]),
),
),
);
}
}
8-18
Widgets Design - Part 2 AFD-200
Important note: Be sure that you have configured the main()function as follows:
runApp(MaterialApp(home: MyApp()));
In following code, you will configure a local variable picked as a DateTime object.
Also, the date picker will start from 1960 until 2030.
In addition, you will configure date1 as a DateTime object and have the current date
(The smart device current date).
The below If statement will enable the setState method which will notify the app
framework that the internal state of DateTime object has been changed when the
user selects a new date value. Then update the values of date1 object.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: MyApp()));
8-19
Flutter ™ Application Development
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(shrinkWrap: true, children: <Widget>[
Row(children: [
Text('Date Value',style: TextStyle(fontSize: 20.0),),
IconButton(
icon: Icon(Icons.date_range),
onPressed: () {
selectDate(context);
},
),
8-20
Widgets Design - Part 2 AFD-200
]),
]),
),
),
);
}
}
If you click the date icon, you will get the date picker dialog box. However, when
you select a new date value and click OK, nothing will happen because you did not
configure any type of the output result yet.
You may add the grey highlighted part of the below code to your app:.
The print method will print the new date value on the run console as illustrated in
the following figure:
8-21
Flutter ™ Application Development
Text(
'Date Value',
style: TextStyle(fontSize: 20.0),
),
Text(
('${date1.year} - ${date1.month} - ${date1.day}').toString(),
style: TextStyle(fontSize: 20.0),
),
The date value will appear as a value of this Text widget with format : year - month -
day format.
11- Run your app again and select a new date value of the date picker. You will get a
date value on your app interface similar to the following figure:
8-22
Widgets Design - Part 2 AFD-200
Time Picker
It is similar to date picker plug-in. Here, you will add an icon to ask the app user to
enter the time value using the time picker plug-in instead of typing it manually.
Example:
In this example, you will follow the same previous steps as that of creating the date
picker app with some changes.
4- Type: time_picker for Project Name and select folder: Lesson_08 for the Project
Location. Click Next
6- Open the main.dart file, delete all its content, and then type the following code:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: MyApp()));
}
8-23
Flutter ™ Application Development
@override
_MyAppState createState() => _MyAppState();
}
setState(() {
time1 = picked;
print(time1.toString());
});
}
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(shrinkWrap: true, children: <Widget>[
Row(children: [
Text(('${time1.hour} : ${time1.minute}').toString(),
style: TextStyle(fontSize: 20.0),),
IconButton(
icon: Icon(Icons.access_time),
onPressed: () {
selectTime(context);
},
),
]),
]),
),
),
);
}
}
8-24
Widgets Design - Part 2 AFD-200
7- Run your app and you will get the following run result:
Slider Widget
The Slider widget selects a single value from a range. As illustrated in the following
figure, you may use Slider widget as a method to input the app user’s information
into the app. You may use this widget to add more user interactivity to your app
such as giving app users control for customizing the app interface and changing
some settings.
8-25
Flutter ™ Application Development
Example:
The following code includes the Slider widget and its properties:
This widget configuration depends on the properties which are used in the previous
code. The following table includes description of each property:
Property Description
Integer represents the number of discrete divisions. In the previous
divisions example, it equals to 4. This means the slider will have 4 values other
than the start or the minimum value.
min The minimum value the user can select.
The maximum value the user can select. Here, in this example, the
max maximum value is 100. It means this slider will be divided into 4
values other than the start value (min value = 0), and the user can
select 0, 25, 50, 75, or 100.
label String value represents a label to show the value above the slider
when the slider is active.
onChanged Called during a drag when the user is selecting a new value for the
slider by dragging.
value The currently selected value for this slider (Double data type).
8-26
Widgets Design - Part 2 AFD-200
Example:
In the following example, you will create a small Flutter app including a Slider
widget. Perform the following steps:
4- Type: slider_picker for Project Name and select Lesson_08 for the Project
Location. Click Next
6- Open the main.dart file, delete all its content, and then type the following code:
import 'package:flutter/material.dart';
8-27
Flutter ™ Application Development
child: Slider(
value: rating,
onChanged: (newRating) {
setState(() => rating = newRating);
},
divisions: 4,
label: "$rating",
min: 0,
max: 100,
),
),
),
Row(children: [
SizedBox(width: 20.0,),
Text(
'Rating Value: '
'$rating',
style: TextStyle(fontSize: 25.0),
),
]),
])),
);
}
}
Important note: The Slider widget container must have a suitable width to show
your app slider on the app interface.
7- Run your app. You should get the following run output. Test your slider values.
8-28
Widgets Design - Part 2 AFD-200
Switch Widget
This widget is used to toggle the on/off state of a single setting. The switch itself
does not maintain any state. Instead, when the state of the switch changes, the
Switch widget calls the onChanged callback function which will rebuild the switch
with a new value to update the visual appearance of the switch.
The following figure displays how Switch widgets look like when they are on or off.
Example:
In the following example, you will create a simple Flutter app including a Switch widget.
8-29
Flutter ™ Application Development
The following configuration will represent the Switch widget on your app interface:
Switch(
value: _value,
onChanged: _onChanged,
),
As you see, this configuration depends on the value (Boolean variable) and
onChanged function. You should configure them before adding Switch widget. The
configuration follows:
6- Open the main.dart file, delete all its content, and then type the following code:
import 'package:flutter/material.dart';
8-30
Widgets Design - Part 2 AFD-200
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Switch Widget'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Switch(
value: _value,
onChanged: _onChanged,
activeColor: Colors.green,
),
Text(
'Value : $_value',
style: TextStyle(fontSize: 20.0),
),
],
),
],
),
),
),
);
}
}
8-31
Flutter ™ Application Development
7- Run your app. Tap the Switch widget (on & off). The run output follows:
AlertDialog Widget
An alert dialog informs the app user about situations that require acknowledgement.
An alert dialog has an optional title and an optional list of actions.
The following figure displays an example of the alert dialog widget and its
properties. The title is displayed above the content and the actions (buttons) are
displayed below the content.
Example:
In this example, you will create a small Flutter app having a button
(RaisedButton). When the app user clicks this button, the AlertDialog will be
generated. This alert dialog box as it is illustrated in the previous figure has a
title, content, and two action buttons.
When the app user taps No, a function will close this alert dialog box, but when
the user taps Yes, two functions will work: the first function will print a text in the
run console, and the second function will close this alert dialog box.
8-32
Widgets Design - Part 2 AFD-200
4- Type: alert_dialog for Project Name and select Lesson_08 folder for the Project
Location. Click Next
6- Open the main.dart file, delete all its content, and then type the following code:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: MyApp()));
}
@override
_MyAppState createState() => _MyAppState();
}
body: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Container(
width: 150,
height: 50,
8-33
Flutter ™ Application Development
child: RaisedButton(
color: Colors.blue,
child: Text(
'Alert Dialog',
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
onPressed: () {
offer(context);
},
),
),
],
),
],
),
),
),
),
);
}
RaisedButton(
color: Colors.blue,
child: Text('No',
style: TextStyle(color: Colors.white, fontSize: 20.0),
8-34
Widgets Design - Part 2 AFD-200
),
onPressed: () => Navigator.pop(context),
),
]);
showDialog(
context: context,
builder: (BuildContext context) {
return alertDialog;
},
);
}
}
7- Run your app, tap the Alert Dialog button, click OK, and check if you got the “Thanks, I
got it.” message at the run console and the alert dialog box has been closed.
8- Reload your app again, tap the Alert Dialog button and click NO. The alert dialog
box must be closed.
9- Don’t close this app because you will use it in the next section.
CupertinoAlertDialog Widget
This widget is similar to the previous AlertDialog widget. However,
CupertinoAlertDialog widget displays the dialog contents that look like
standard iOS dialog buttons, and titles as illustrated in the following figure:
A red underline will appear under the CupertinoAlertDialog widget. To fix this
error, double click the CupertinoAlertDialog widget, click the red lamp icon, and
8-35
Flutter ™ Application Development
then select:
Then run your app again. You will get the CupertinoAlertDialog dialog box and
find that its buttons work similarly as the AlertDialog widget in the previous
example.
There are two types of bottom sheets in material design, Modal and Persistent
bottom sheets. In the following section of this lesson, you will learn in details about
the differences between, and how to configure the modal and persistent bottom
sheets in Flutter:
8-36
Widgets Design - Part 2 AFD-200
Example:
In this example, you will create a small Flutter app including a raised button. When
the app user clicks this button, he/she will get a modal bottom sheet.
4- Type: bottom_sheet for Project Name and select Lesson_08 folder for the Project
Location. Click Next
6- Open the main.dart file, delete all its contents, and then type the following code:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: MyApp()));
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Alert Dialog Widget'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Container(
width: 200,
height: 50,
8-37
Flutter ™ Application Development
child: RaisedButton(
color: Colors.blue,
child: Text('Bottom Sheet',
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
onPressed: () {
},
),
),
],
),
],
),
),
),
),
);
}
}
7- In this step, you will create the modal bottom sheet using the
showModalBottomSheet function. Create this function and use a Container widget
with a specific height to represent the bottom sheet body. You may add a child
widget to this Container widget to present the bottom sheet content. The function
code follows:
_showModalBottomSheet(context) {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 200.0,
alignment: Alignment.topCenter,
child: Text(
'Android ATC',
style: TextStyle(
fontSize: 20.0,
),
),
);
});
}
8-38
Widgets Design - Part 2 AFD-200
8- Configure a raised button to call this function when the app user taps this button.
The full code of this app follows:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: MyApp()));
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Alert Dialog Widget'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Container(
width: 200,
height: 50,
child: RaisedButton(
color: Colors.blue,
child: Text('Bottom Sheet',
8-39
Flutter ™ Application Development
9- Run your app, click the button and you will get the modal bottom sheet as
illustrated in the following figure. To close this bottom sheet and return to your app
content, just click on any area of the app interface above this bottom sheet.
8-40
Widgets Design - Part 2 AFD-200
Example:
In this example, you will create a small Flutter app including two raised buttons as
illustrated in the following figure:
When the app user taps the Bottom Sheet button, he/she will get the Persistent
bottom Sheet which has at Text widget: “Welcome to Android ATC”, and at the same
time the app user can tap the Test Button or any other part of this app within the
Persistent bottom sheet while it is active. This is the main difference between the
Persistent bottom sheet and the Modal bottom sheet.
8-41
Flutter ™ Application Development
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: MyApp()));
}
@override
_MyAppState createState() => _MyAppState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Persistent Bottom Sheet'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Container(
width: 200,
height: 50,
child: RaisedButton(
color: Colors.blue,
child: Text('Bottom Sheet',
8-42
Widgets Design - Part 2 AFD-200
style:
TextStyle(color: Colors.white, fontSize: 20.0),
),
onPressed: () {}
),
),
],
),
SizedBox(height: 20.0,),
Row(
children: <Widget>[
Container(
width: 200,
height: 50,
child: RaisedButton(
color: Colors.blue,
child: Text('Test Button',
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
onPressed: () {},
),
),
],
),
],
),
),
),
),
);
}
}
7- Run your app and you will get the following run output:
8-43
Flutter ™ Application Development
@override
void initState() {
super.initState();
_showpersistentSheet = _sheetBottomSheet;
}
void _sheetBottomSheet() {
setState(() {
_showpersistentSheet = null;
});
_scaffoldkey.currentState
.showBottomSheet((content) {
return Container(
color: Colors.blue,
height: 200,
child: Center(
child: Text(
'Welcome to Android ATC',
style: TextStyle(fontSize: 20, color: Colors.white),
),
),
); //Container
})
.closed
.whenComplete(() {
if (mounted) {
setState(() {
_showpersistentSheet = _sheetBottomSheet;
});
}
});
}
8-44
Widgets Design - Part 2 AFD-200
Explanation:
This part of the code configures _scaffoldkey as a global key which will be added
to the Scaffold widget in your app to make a connection between the Scaffold
widget and this bottom sheet.
The widgets that have global keys re-parent their sub-trees when they are moved
from one location in the tree to another location in the same tree. In order to re-
parent its sub-tree, a widget must arrive at its new location in the tree in the same
animation frame in which it was removed from its old location in the tree.
Also, this part of the code created the function : _showpersistentSheet which will
be called later by the “Bottom Sheet” button.
8-45
Flutter ™ Application Development
child: RaisedButton(
color: Colors.blue,
child: Text('Bottom Sheet',
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
onPressed: _showpersistentSheet,
),
),
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: MyApp()));
}
@override
_MyAppState createState() => _MyAppState();
}
8-46
Widgets Design - Part 2 AFD-200
@override
void initState() {
super.initState();
_showpersistentSheet = _sheetBottomSheet;
}
void _sheetBottomSheet() {
setState(() {
_showpersistentSheet = null;
});
_scaffoldkey.currentState
.showBottomSheet((content) {
return Container(
color: Colors.blue,
height: 200,
child: Center(
child: Text(
'Welcome to Android ATC',
style: TextStyle(fontSize: 20, color: Colors.white),
),
),
);
})
.closed
.whenComplete(() {
if (mounted) {
setState(() {
_showpersistentSheet = _sheetBottomSheet;
});
}
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
key: _scaffoldkey,
appBar: AppBar(
title: Text('Persistent Bottom Sheet'),
),
body: Center(
child: Padding(
8-47
Flutter ™ Application Development
SizedBox(height: 20.0,),
Row(
children: <Widget>[
Container(
width: 200,
height: 50,
child: RaisedButton(
color: Colors.blue,
child: Text('Test Button',
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
onPressed: () {},
),
),
],
),
],
),
),
),
),
);
}
}
8-48
Widgets Design - Part 2 AFD-200
11- Run your app. Click the Bottom Sheet button to get the bottom sheet.
It should be noted that you can still click the Text Button even though the bottom sheet
is working. This is the main difference between Persistent and Modal bottom sheets. If
this bottom sheet was Modal type, you could not have tapped this Text Button.
Tap the white arrow on your app title bar and if you click the Bottom Sheet button
again, you will find that it works fine.
only visible when it is expanded. This widget is used to display information about a
list of items and if the app user needs more information or details about a specific
item, he/she will tap the item arrow sign to expand it. The following figure displays
how the ExpansionPanel widget looks like:
8-49
Flutter ™ Application Development
Example:
In this example, you will create a small Flutter app using the ExpansionPanelList
class which lays out its items and builds their contents using the
ExpansionPanel widget.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: MyApp()));
}
@override
_MyAppState createState() => _MyAppState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Expansion Panel'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: <Widget>[
],
8-50
Widgets Design - Part 2 AFD-200
),
),
),
);
}
}
7- Run your app. You should get an empty interface and have only the title bar:
Expansion Panel
8- Create a new class including each expanding item components such as header
and body. In this example, this class is called : MyItem
class MyItem {
MyItem({this.isExpanded: false, this.header, this.body});
bool isExpanded;
final String header;
final String body;
}
9- Use the MyItem class to configure _items object as a list. Each header and body
of this list represent one item of the expansion panel items.
In this example, this _items list declares four headers and bodies as illustrated in
the following code:
List<MyItem> _items=<MyItem>[
MyItem(header:"Header 1", body: "Body 1"),
MyItem(header:"Header 2", body: "Body 2"),
MyItem(header:"Header 3", body: "Body 3"),
MyItem(header:"Header 4", body: "Body 4"),
];
8-51
Flutter ™ Application Development
The following figure displays where exactly you must add this code:
10 - Now, you will add the ExpansionPanelList widget to configure the expansion
items layout and add the ExpansionPanel widget which is responsible to configure
and add the values of the _items list to the expansion panel items. You should
configure these two widgets as children widgets of the ListView widget.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: MyApp()));
}
@override
_MyAppState createState() => _MyAppState();
}
class MyItem {
8-52
Widgets Design - Part 2 AFD-200
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Expansion Panel'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: <Widget>[
ExpansionPanelList(
expansionCallback: (int index, bool isExpanded) {
setState(() {
_items[index].isExpanded = !_items[index].isExpanded;
});
},
children: _items.map((MyItem item) {
return ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) {
return Text(
item.header,
style: TextStyle(fontSize: 30, color: Colors.blue),
);
},
isExpanded: item.isExpanded,
body: Container(
child: Text(
item.body,
style: TextStyle(fontSize: 20, color: Colors.blue),
),
8-53
Flutter ™ Application Development
));
}).toList(),
)
],
),
),
),
);
}
}
11- Run your app and test your expansion panel by expanding and collapsing its
items.
SnackBar widget is used if you want to let your app pop up a message for a few
seconds at the bottom of your app interface. The following figure displays how and
where the SnackBar message looks like.
An example of SnackBar message is when you send an email using the Gmail app,
you usually get a message at the bottom of your phone device as a notification
telling you that your message has been sent.
This notification message appears temporarily for seconds and then it is hidden
automatically.
In this section, you will add a SnackBar widget to your app code, configure the
notification message content, message duration, and configure the action which will
generate this notification message.
8-54
Widgets Design - Part 2 AFD-200
Example:
In this example, you will create a small Flutter app including a raised button. When
the app user taps this button, a SnackBar message appears at the bottom of the
smart device.
8-55
Flutter ™ Application Development
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: MyApp()));
}
@override
_MyAppState createState() => _MyAppState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Snack Bar Widget'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
color: Colors.blue,
child: Text('Notification Message',
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
onPressed: () {},
),
),
),
);
}
}
7- Run your app. You should get an interface including a raised button only without
any action.
8- Now, create a new function called _showSnackBar() which includes the SnackBar
8-56
Widgets Design - Part 2 AFD-200
widget configurations such as message content, duration and the Scaffold key.
You should add these configurations directly below the following code:
SizedBox(width: 10.0,),
SizedBox(
child: Text('Hey I am a SnackBar !',
style: TextStyle(fontSize: 20, color: Colors.white),
),
),
],
),
duration: Duration(seconds: 3),
backgroundColor: Colors.blue,
);
_scaffoldKey.currentState.showSnackBar(snackBar);
}
9- Add the Scaffold key to the Scaffold widget by adding the grey highlighted part of
the following code:
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text('Snack Bar Widget'),
8-57
Flutter ™ Application Development
10- The last step is configuring the raised button to generate the SnackBar
message when the app user taps this button. Configure this button as follows:
onPressed: _showSnackBar,
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: MyApp()));
}
@override
_MyAppState createState() => _MyAppState();
}
SizedBox(width: 10.0,),
SizedBox(
child: Text('Hey I am a SnackBar !',
style: TextStyle(fontSize: 20, color: Colors.white),
),
),
],
),
duration: Duration(seconds: 3),
backgroundColor: Colors.blue,
);
_scaffoldKey.currentState.showSnackBar(snackBar);
}
8-58
Widgets Design - Part 2 AFD-200
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text('Snack Bar Widget'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
color: Colors.blue,
child: Text('Notification Message',
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
onPressed: _showSnackBar,
),
),
),
);
}
}
11- Run your app, tap the button and check the SnackBar notification message
which will appear at the bottom of your app interface for 3 seconds as illustrated in
the following figure:
8-59
Flutter ™ Application Development
The following figure includes two interfaces of the app which you will create. The
first interface includes a form asking the app user to enter what he/she needs, and
when the app user clicks the button at the end of this form, he/she will be directed
to another interface including an expansion panel widget. This expansion widget
includes images of room categories and some details or information about each
room (expansion panel item).
To create this app, perform the following actions step by step. Or if you don’t have
enough time, you may use the lab source code for this lab to test how it works.
8-60
Widgets Design - Part 2 AFD-200
4- Type : lab_08 for Project Name and create a new folder : Lab_08 for the Project
Location. Click Next
6- Right click the lib folder (lab_08→ lib) and select New → Dart File
As illustrated in the following figure, type: home for the file name and then click OK
7- Repeat the same previous step to add a new Dart file: roomsPanel.dart
8 - Open home.dart file and add the following code which will add the basic
components to this app interface such as the title bar and a Container widget. This
is just to be sure that the design works fine. The code is the following:
import 'package:flutter/material.dart';
8-61
Flutter ™ Application Development
);
}
}
10- Open the roomsPanel.dart file and paste the code of home.dart in roomsPanel.dart file.
12- Open main.dart file and Delete all its code contents. The main.dart will be
configured to include the navigation names only. Open main.dart and type the
following code:
import 'package:flutter/material.dart';
import 'home.dart';
import 'roomsPanel.dart';
13- Run your app. You should get the content of home.dart file which includes a
simple interface just containing the title bar and the text “Home”.
14- Add “images” directory to your project. Right click your project name (lab_08)
then select: New → New Directory. Then type the directory name “images”, and then
click OK as illustrated in the following figure:
8-62
Widgets Design - Part 2 AFD-200
15- Open the pubspec.yaml file and configure images directory to be the default
location for all your images in this app. Just remove the hash sign for assets and
configure the images directory name as illustrated in the following figure:
16- Your computer should have the lab source files for this course. Open the following
path on your computer: Lab Source Files\Images\Lab 8, copy all the image files, right
click the images directory in your app, select paste and then click OK.
17- Open home.dart and you should design the following interface which will ask the
app user to reserve a room depending on specific criteria.
8-63
Flutter ™ Application Development
In the home.dart file, add the following code to its body property :
body: Padding)
padding: const EdgeInsets.all)8.0(,
child: Column)children: <Widget>[
Row)
children: <Widget>[
Image)
alignment: Alignment.topCenter,
width: 350.0,
image: AssetImage)'images/entrance.jpg'(,
(,
],
(,
Row)
// This row for Check-in Date : Android ATC - Lab 8
children: <Widget>[
Text)'Check-in Date : ',
style: TextStyle)
fontSize: 20.0,
8-64
Widgets Design - Part 2 AFD-200
color: Colors.deepOrange,
fontWeight: FontWeight.bold,
),
),
And then, click the orange lamp and select : Convert to StatefulWidget
19- You will now add the following code to configure the hotel check-in date for the
app user. In home.dart file, click directly below the following line of code:
8-65
Flutter ™ Application Development
setState(() {
checkInDate = picked;
});
}
}
20- In home.dart file, you will add the code to display the value of the selected
check-in Date.
Text(
('${checkInDate.year} - ${checkInDate.month} - ${checkInDate.day}')
.toString(),
style: TextStyle(fontSize: 20.0, color: Colors.blue),
),
IconButton(
icon: Icon(
Icons.date_range,
color: Colors.deepOrangeAccent,),
onPressed: () {
selectDate(context);
},
),
8-66
Widgets Design - Part 2 AFD-200
21- Run your app and test the check-in section. At this stage, you should get the
following figure :
22- Now, you should add the check-out section. Open home.dart file and directly
above the following code:
@override
Widget build(BuildContext context) {
8-67
Flutter ™ Application Development
23- Under the Row which represents the Check-in date, add a new Row widget
including the following code:
Row(
// This row for Check-out Date
children: <Widget>[
Text('Check-Out Date : ',
style: TextStyle(
fontSize: 20.0,
color: Colors.deepOrange,
fontWeight: FontWeight.bold,
),
),
Text(
('${checkOutDate.year} - ${checkOutDate.month} -
${checkOutDate.day}')
.toString(),
style: TextStyle(fontSize: 20.0, color: Colors.blue),),
IconButton(
icon: Icon(
Icons.date_range,
color: Colors.deepOrangeAccent,),
onPressed: () {
selectDate2(context);
},
),
],
)
24- Now, in home.dart , you will add two Slider widgets to represent the number of
adults and children. Before configuring these slider widgets, configure the following
two variables (adult_Number and child_Number) directly above the following :
@override
Widget build(BuildContext context) {
8-68
Widgets Design - Part 2 AFD-200
25- In home.dart , add the following two Row widgets to configure two sliders to
your app interface.
This code must be written after closing the Row widget which wraps the Check-out date.
Row(
children: <Widget>[
Text(
'Adults: '
'$adult_Number',
style: TextStyle(
fontSize: 20.0,
color: Colors.deepOrange,
fontWeight: FontWeight.bold,
),
),
Container(
width: 250.0,
child: Slider(
value: adult_Number,
onChanged: (newRating) {
setState(() => adult_Number = newRating);
},
divisions: 6,
label: '$adult_Number.Adult',
min: 0,
max: 6,
),
),
],
),
Row(
children: <Widget>[
8-69
Flutter ™ Application Development
Text(
'Children: '
'$child_Number',
style: TextStyle(
fontSize: 20.0,
color: Colors.deepOrange,
fontWeight: FontWeight.bold,
),
),
Container(
width: 250.0,
child: Slider(
value: child_Number,
onChanged: (newRating) {
setState(() => child_Number = newRating);
},
divisions: 6,
label: '$child_Number.Children',
min: 0,
max: 6,
),
),
],
),
8-70
Widgets Design - Part 2 AFD-200
27- Before adding the checkboxes and radio buttons to your app, it is recommended
to wrap your app body’s entire content using a ListView widget to avoid any
problem in vertical scrolling of your app interface.
To do that, make the parent widget for your app body as ListView , and then
wrap the ListView widget using the Padding widget to get a margin for your app
interface content.
Modify your body code to be as illustrated in the following figure:
28- To add a group of checkboxes and radio buttons to your app interface, you
should configure the pubspec.yaml file as follows:
grouped_buttons: ^1.0.4
29- Now, add the following code to add the checkboxes and radio buttons which are
8-71
Flutter ™ Application Development
To do that, add the following code after closing the last Row widget (Slider widget).
Row(
children: <Widget>[
Text(
'Extras :',
style: TextStyle(
fontSize: 20.0,
color: Colors.deepOrange,
fontWeight: FontWeight.bold,
),
),
],
),
Container(
height: 200.0,
child: CheckboxGroup(
labelStyle: TextStyle(fontSize: 20.0),
labels: <String>[
"Breakfast (10 USD/Day)",
"Internet WiFi (5 USD/Day)",
"Parking (5 USD/Day)",
"Swimming Pool (10 USD/Day)",
],
onSelected: (List<String> checked) =>
8-72
Widgets Design - Part 2 AFD-200
print(checked.toString()),
),
),
Row(
children: <Widget>[
Text('View :',
style: TextStyle(
fontSize: 20.0,
color: Colors.deepOrange,
fontWeight: FontWeight.bold,
),
),
],
),
Container(
child: RadioButtonGroup(
orientation: GroupedButtonsOrientation.VERTICAL,
labelStyle: TextStyle(fontSize: 20.0),
labels: <String>[
"City View",
"Sea View",
],
onSelected: (String selected) => print(selected),
),
),
30- You will get a red underline below CheckboxGroup widget. Double click this
widget, click the red lamp, and then select the following choice as illustrated in the
following figure:
8-73
Flutter ™ Application Development
31 - Run your app to be sure that you get the first app interface.
32- Now, you will add the last part of your first app interface which is a search
button.
The code for this Row and RaisedButton widgets follows. When the app user
taps this button, he/she will move to roomsPanel.dart file contents. You already
configured the navigation configurations for your app in the main.dart file.
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
color: Colors.deepOrange,
child: Text(
'Check Rooms and Rates',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.bold),
),
onPressed: () {
Navigator.pushNamed(context, 'RoomsPanel');
},
),
],
),
33- Run your app and scroll down the interface. You should get the following figure:
8-74
Widgets Design - Part 2 AFD-200
34- Open roomsPanel.dart file and then double click the StatelessWidget{ of the
following code:
Note: Before typing the code of roomsPanel.dart file, you should understand what you
will do here. This Expansion Panel will display text and images depending on its work on
a class called NewItem in this lab. This class includes four variables which are:
8-75
Flutter ™ Application Development
selection (String): Represents the text which will appear beside the image.
body (String): The text which will appear in the expanded area of the expansion panel.
The class code follows (Don't type the following code in your lab):
class NewItem {
bool isExpanded;
final Widget header;
final String selection;
final String body;
NewItem(
this.isExpanded,
this.header,
this.selection,
this.body,
);
}
Also, you will use a list called items which will have the values of the class items
(header, selection and body). You may add more items to this list as you have data.
import 'package:flutter/material.dart';
class NewItem {
bool isExpanded;
final Widget header;
final String selection;
final String body;
NewItem(
8-76
Widgets Design - Part 2 AFD-200
this.isExpanded,
this.header,
this.selection,
this.body,
);
}
NewItem(
false,
Container(
child: Image(
height: 100,
width: 200,
image: AssetImage('images/1bed.jpg'),
),
),
"King Room",
"A room with a king-sized bed."),
NewItem(
false,
Container(
child: Image(
height: 100,
width: 200,
image: AssetImage('images/2beds.jpg'),
),
),
"Double Room",
"A room assigned to two people."),
NewItem(
false,
Container(
child: Image(
height: 100,
width: 200,
image: AssetImage('images/3beds.jpg'),
),
),
"Family Room",
"A room assigned to three or four people."),
];
8-77
Flutter ™ Application Development
ListView List_Criteria;
Widget build(BuildContext context) {
List_Criteria = new ListView(
children: [
new Padding(
padding: new EdgeInsets.all(10.0),
child: new ExpansionPanelList(
expansionCallback: (int index, bool isExpanded) {
setState(() {
items[index].isExpanded = !items[index].isExpanded;
});
},
children: items.map((NewItem item) {
return new ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) {
return new ListTile(
leading: item.header,
title: new Text(
item.selection,
textAlign: TextAlign.left,
style: new TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
color: Colors.orangeAccent,
),
));
},
isExpanded: item.isExpanded,
body: Text(
item.body,
style: TextStyle(
fontSize: 20,
color: Colors.black,
),
),
);
}).toList(),
),
)
],
);
8-78
Widgets Design - Part 2 AFD-200
),
),
body: List_Criteria,
persistentFooterButtons: <Widget>[
ButtonBar(children: <Widget>[
RaisedButton(
color: Colors.orange,
child: Text('Next',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.bold),
),
onPressed: () {},
),
]),
],
);
return scaffold;
}
}
37- Run your app. Tap the button : Check Rooms and Rates and expand the
expansion panel by tapping the arrow signs.
You may add additional configurations to this app such as when the app user taps
the Next button, he/she will move to another interface (for example reserve.dart file)
to enter his/her personal information or generate an alert dialog box.
8-79
Firebase AFD-200
Lesson 9: Firebase
Introduction............................................................................................................................ 9-2
What is the JSON ?................................................................................................................ 9-3
How does Firebase Database work?..................................................................................... 9-4
Firebase authentication (Signup and Login to Flutter App)................................................ 9-5
Configure Your App to use Firebase Services...................................................................... 9-17
Adding Firebase to your Android App.............................................................................. 9-19
Adding Firebase to your iOS App..................................................................................... 9-26
Configuring Firebase Authentication.................................................................................... 9-33
Login to an App Using Firebase User Accounts.............................................................. 9-46
Logout Configuration........................................................................................................ 9-48
Firebase Database................................................................................................................. 9-53
Which database is right for your project?........................................................................ 9-53
Real Time Database.......................................................................................................... 9-54
Cloud Firestore.................................................................................................................. 9-63
Lab 9 : Create a User Profile Interface using Firebase........................................................ 4-72
9-1
Flutter ™ Application Development
Introduction
Firebase is a NoSQL document database that simplifies storing, syncing, and
querying data for your Android, iOS, and web apps at a global scale. Its client
libraries provide live synchronization and offline support, while its security features
and integrations with the Firebase and Google Cloud platforms accelerate building
truly server-less apps.
1- Authentication
Most apps require to know the identity of the user. Firebase Authentication provides
backend services, easy-to-use SDKs, and ready-made UI libraries to authenticate
users to your app. It supports authentication using passwords, phone numbers,
popular federated identity providers like Google, Facebook, Twitter and more. In
Firebase Authentication, developers can define who has access to what data, and
how they can access it. In this lesson, you will learn how to configure your Flutter
app by using this feature in order to create user accounts on Firebase and how to
login to your app using these accounts.
2- Realtime Database
The Firebase Realtime Database is a cloud-hosted database. Data is stored as
JSON and is synchronized in real time to every connected client. In this lesson, you
will configure your app to user Firebase real time database to save app data and
retrieve (query) the existing Firebase data.
9-2
Firebase AFD-200
3- Cloud Firestore
Cloud Firestore is a flexible, scalable database for mobile, web, and server
development from Firebase and Google Cloud Platform. Like Firebase Realtime
Database, Cloud Firestore keeps your data in sync across client apps through real
time listeners and offers offline support for mobile and web applications so you
can build responsive apps that work regardless of network latency or Internet
connectivity. Cloud Firestore also offers seamless integration with other Firebase
and Google Cloud Platform products, including Cloud Functions. In this lesson,
you will learn how to create a cloud Firestore database and how to use this data in
Flutter app.
4- Cloud Storage
Cloud Storage for Firebase is a powerful, simple, and cost-effective object storage
service built for Google scale. The Firebase SDKs for Cloud Storage adds Google
security to file uploads and downloads for your Firebase apps, regardless of network
quality. You can use our SDKs to store images, audio, video, or other user-generated
content.
Firebase provides other services and products which are all important for
mobile and web development domains such as hosting, cloud functions, test
lab, ML Kit, analytics, predictions, and others. To get more details about other
Firebase products, check the following web site: https://firebase.google.com/
products#develop-products
Google allows web sites, mobile apps, and other media to connect to its database
and import it in JSON format. For example, Google maps database is available
to import or use by iOS, Android, and web apps in JSON format. Also, these apps
establish connection with Google database using https connection and API key as
you will see in the next lesson (Using GPS and Google Maps).
9-3
Flutter ™ Application Development
You can customize your import of the Google database by selecting whatever object
you want it to appear on your app content .
JSON objects are surrounded by curly braces {} and they are written in key/value pairs.
Keys must be string and values must be a valid JSON data type (string, number,
array, Boolean or null).
In this lesson, you will get more information about how to configure your app to use
JSON in access Firebase database.
Firebase apps remains responsive even when it is offline because the Firebase
Database SDK keeps your data on the device storage. When the device regains
connection, the Database synchronizes the local data changes with the remote
updates that occurred while the client was offline, merging any conflicts
automatically.
The Firebase Database can be accessed directly from a mobile device or web
browser. Therefore, there is no need for an application server. Security and
data validation are available through the Firebase Database Security Rules and
expression-based rules that are executed when data is read or written.
Unlike an SQL database, in Firebase database, there are no tables or rows. Instead, you
store data in documents, which are organized into collections. Each document contains a
set of key-value pairs (data) as you will see later in this lesson.
9-4
Firebase AFD-200
The Firebase Database lets you build rich, collaborative applications by allowing
secure access to the database directly from client-side code.
When you work with Firebase database, you will find there are two types of Firebase
database, Realtime Firebase database and Cloud Firestore. Later in this lesson, you
will know in details about the difference between Firebase Realtime database and
Cloud Firestore.
In this lesson, we are going to mostly be concerned with cloud Firestore which is the
latest way of using Firebase to store data in the cloud. We are also going to be using the
authentication package so that you can design an app, which allows app users to register
their accounts (Signup) and login to this app using their credentials (User Login).
Most apps need to know the identity of a user. Knowing a user’s identity allows an
app to securely save his/her data in the cloud and provide the same personalized
experience across all of the user’s devices.
The following figure includes a diagram of the Flutter app which you will create :
9-5
Flutter ™ Application Development
As you see in the previous diagram, you will create a home interface (home.dart)
which includes two buttons. The first button is (New User Account) to create a new
user account . This account consists of a user name (email) and password which
will be created at Firebase web. The second button in home.dart will be for login
(Login). When the app user taps the login button, he/she will be asked to enter the
user name and the password which the app user has created before. Then, when the
app user taps the Login button, this credential information (user name & password)
will be sent to Firebase to check the authentication. If they are correct, then the user
can login or move to another app interface (service.dart) to use the app services
which are in the interface (Service Interface).
Note: In this app, you will use a TextField widget. If you need more details about
using this widget, please review lesson 8.
9-6
Firebase AFD-200
6- Now, you should create three new interfaces (Dart files). Right click the lib folder,
and select: New → Dart File . Type home for the file name , and then click OK.
7- Repeat the previous step to create another two dart files new_account.dart and
service.dart.
8- In the new_account.dart file, create an interface having two text fields to ask
the app user to enter his/her username, password, and then click create button as
illustrated in the following figure:
import 'package:flutter/material.dart';
9-7
Flutter ™ Application Development
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('New Account '),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ListView(
shrinkWrap: true,
children: <Widget>[
Container(
alignment: Alignment.center,
child: Text(
'New User Account',
style: TextStyle(
fontSize: 40,
color: Colors.blue,
fontWeight: FontWeight.bold,),
),
),
SizedBox(height: 10.0,),
SizedBox(width: 20.0,),
SizedBox(width: 220.0,
child: TextField(
onChanged: (value) {},
style: TextStyle(fontSize: 20, color: Colors.blue),
keyboardType: TextInputType.emailAddress,
9-8
Firebase AFD-200
textInputAction: TextInputAction.done,
autocorrect: false,
cursorColor: Colors.red,
decoration: InputDecoration(
hintText: 'Your Email',
),
),
),
],
),
SizedBox(height: 10.0,),
child: TextField(
onChanged: (value) {},
//obscureText: true,
style: TextStyle(fontSize: 20, color: Colors.blue),
textInputAction: TextInputAction.done,
autocorrect: false,
),
),
],
),
SizedBox(height: 10.0,),
Center(
child: Container(
width: 100,
child:RaisedButton(
color: Colors.blue,
child: Text("Create",
9-9
Flutter ™ Application Development
style:TextStyle(fontSize:20,color: Colors.white),),
onPressed: () {},
),
),
),
],
),
],
),
),
),
);
}
}
9- Open login.dart file and add the code which creates a login interface. The app
user will use this interface to login using the user name and password which he/she
has created in the create interface. The login interface is illustrated in the following
figure:
You may copy the code of the new_account.dart file and then paste it in the login.dart
9-10
Firebase AFD-200
file and change the classes names, title bar, and other text values which are illustrated in
the grey highlighted color in the following code or type all the code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ListView(
shrinkWrap: true,
children: <Widget>[
Container(
alignment: Alignment.center,
child: Text('Login',
style: TextStyle(
fontSize: 40,
color: Colors.blue,
fontWeight: FontWeight.bold,),
),
),
SizedBox(height: 10.0,),
9-11
Flutter ™ Application Development
SizedBox(width: 20.0,),
SizedBox(width: 220.0,
child: TextField(
onChanged: (value) {},
style: TextStyle(fontSize: 20, color: Colors.blue),
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.done,
autocorrect: false,
cursorColor: Colors.red,
decoration: InputDecoration(hintText: 'Your Email',
),
),
),
],
),
SizedBox(height: 10.0,),
child: TextField(
onChanged: (value) {},
//obscureText: true,
style: TextStyle(fontSize: 20, color: Colors.blue),
textInputAction: TextInputAction.done,
autocorrect: false,
),
),
],
),
9-12
Firebase AFD-200
SizedBox(height: 10.0,),
Center(
child: Container(
width: 100,
child:RaisedButton(
color: Colors.blue,
child: Text("Login",
style:TextStyle(fontSize:20,color:
Colors.white),),
onPressed: () {},
),
),
),
],
),
],
),
),
),
);
}
}
10- Open the service.dart file and type the following code. This interface should
include the app services which the user login for.
import 'package:flutter/material.dart';
9-13
Flutter ™ Application Development
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Android ATC Services'),
),
body: Center(
child: Container(
child: Text('Welcome to Android ATC',
style: TextStyle(fontSize: 20.0,
),),
),
),
),
);
}
}
11- Open main.dart and delete all its content and then type the following code which
includes the navigation routes. During the startup of the app, this main file will
forward the app users to home.dart interface.
import 'login.dart';
import 'new_account.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'home.dart';
import 'service.dart';
9-14
Firebase AFD-200
return MaterialApp(
home: Home(),
routes: {
'Login': (context) => Login(),
'NewAccount': (context) => NewAccount(),
'Service': (context) => Service(),
},
);
}
}
12- Open home.dart file. This interface is the startup interface for your app as
illustrated in the following figure. When the app user taps on the New User Account
button, he/she will move to the new_account.dart file and when the app user clicks
on Login button, he/she will move to login.dart.
9-15
Flutter ™ Application Development
import 'package:flutter/material.dart';
import 'new_account.dart';
import 'login.dart';
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
color: Colors.blue,
child: Text('New User Account',
style: TextStyle(fontSize: 20, color: Colors.white),),
onPressed: () {
Navigator.pushNamed(context, 'NewAccount');
},
),
SizedBox(height:40.0,),
RaisedButton(
color: Colors.blue,
child: Text('Login',
style: TextStyle(fontSize:20,color:Colors.white),),
9-16
Firebase AFD-200
onPressed: () {
Navigator.pushNamed(context, 'Login');
},
),
],
),
),
),
);
}
}
13- Run your app and check your navigation buttons (New User Account & Login).
9-17
Flutter ™ Application Development
17- Click Get Started and click Create a project . Fill out your project name “firebase
authentication” or any other name. Check I accept the Firebase terms and then click
Continue as illustrated in the following figure:
18- Click Enable Google Analytics for this project to disable this feature, because this
app is just for testing how Firebase authentication works. However, these Google
features are important for releasing a report about your live apps in the future.
Click Create Project. Then, after seconds, you should get the following message as
illustrated in the following figure telling you that your project has been created on
Google Firebase. Click Continue
9-18
Firebase AFD-200
19- Now, as you see in the following figure, your project name: firebase
authentication is created at the Firebase and if you click Develop on the left scroll
frame, you will get all the Firebase services which you may use for your app.
20- To add Firebase services to your Android, you should click the Android icon in
the previous step, then click iOS icon to add these services to iOS app.
You should get the following dialog box to register your app. As you will see below, you
should enter your project name which must be a unique name in Google Play store.
9-19
Flutter ™ Application Development
If you forgot your app name, go to : Android Studio and open the following path:
Then, scroll down the file content, as illustrated in the grey highlighted part of the
application Id in following code, your app name appears:
defaultConfig {
// TODO: Specify your own unique Application ID (https://
developer.android.com/studio/build/application-id.html).
applicationId "com.androidatc.firebase_authentication"
minSdkVersion 16
targetSdkVersion 28
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.
AndroidJUnitRunner"
}
9-20
Firebase AFD-200
Here, you found com.androidatc because when you created this Flutter app, you
typed androidatc.com as your domain name. With your app, if you don’t have a
domain name, just type yourname.com or .net.
21- Copy the application Id, go to the Firebase website, paste it in your Android
package name, and then click Register app button as illustrated in the following
figure:
22- In this step, as illustrated in the following figure, you should click:
Download google-service.json button to download the JSON configuration file. This
configuration file includes the https connection settings between your Android app
and the Firebase services. If you download this file many times, you should use the
file which has exactly this name : google-services.json without any number.
9-21
Flutter ™ Application Development
23- Move this file : google-services.json from your download folder to app folder
using drag and drop technique. This app folder exists in Android Studio in the
following path:
9-22
Firebase AFD-200
If you expand the app folder, you will find this json file added to your Android app as
illustrated in the following figure:
24- Now, return to the Firebase web site to complete the setup steps. Click Next.
25- In the Add Firebase SDK step , copy the line which is illustrated in the following
figure, or click the copy icon.
9-23
Flutter ™ Application Development
26- In Android Studio, open the build.gradle file which exists in the following path :
And paste this class path within the dependencies braces as illustrated in the
following figure:
27- Now, return to the Firebase web site and from the configuration wizard, copy the
following two lines :
Go to Android Studio, open the build.gradle file which is in the following path:
Then, paste the other two lines as separate lines at the end of this file as illustrated
in the following figure:
Also, in the same build.gradle file add : multiDexEnabled true as illustrated in the
grey highlighted part of the following configuration:
9-24
Firebase AFD-200
defaultConfig {
28- Now, close all your Gradle files and be sure that your Android emulator is
selected. Now, stop your app and then run your app again to apply the changes in
your Android Studio Gradle files.
29- Return to your Firebase configuration web page, click Next and you will get the
following figure:
9-25
Flutter ™ Application Development
30 - Click Continue to console, then you will get the following figure:
Your Flutter app is creating the Android and iOS apps simultaneously. Now, as
you see, your Android app is configured with Firebase. Now, your Android app is
ready to exchange or use the Firebase plug-in services, such as database or user
authentication services.
In Firebase web site, click +Add app button and then click iOS icon as illustrated in
the following figure:
9-26
Firebase AFD-200
32- You will get the following wizard which asks you to enter the iOS bundle ID, or
the app name.
Here, the iOS app name is Not the same name as Android package name. When
you configured you Android app with Firebase , you used the following Android
package name: com.androidatc.firebase_authentication , but iOS doesn’t accept the
underscore symbol.
To find your iOS app name (iOS bundle name), open the following path in Android
Studio:
Double click this file : project.pbxproj , scroll down or press Ctrl + F to find the
following :
PRODUCT_BUNDLE_IDENTIFIER = com.androidatc.firebaseAuthentication;
33- Copy this iOS bundle id, and paste it in your Firebase and iOS app configuration
wizard as illustrated in the following figure. Please don’t add a space before or after
this bundle id. Then, click Register app button.
9-27
Flutter ™ Application Development
35- Drag this downloaded file (GoogleService-Info.plist) to Android Studio and drop
it inside the Runner folder which is illustrated in the following figure:
9-28
Firebase AFD-200
If you are using a Mac computer and want to update these changes, select your
IPhone emulator, stop your app, and then run it again.
36- Return to Firebase configuration wizard in your web browser and click Next.
9-29
Flutter ™ Application Development
37-Now, in this step : Add Firebase SDK as illustrated in the following figure:
CocoaPods is a dependency manager for Swift and Objective-C which will help you
to install third-party packages like Firebase to your Xcode project.
Because you are using Flutter, it is actually going to do this step for you
automatically. So, you do NOT need to perform any of these commands. Instead,
you may go back to your Android Studio, change your emulator type to the IPhone
simulator (or connected IPhone physical device), then click run to build your app .
You should get the following run result:
9-30
Firebase AFD-200
Return to your web browser (Add Firebase to your iOS app) and click Next.
38-In this step, (Add initialization code) and as you see in the following figure you
should add two lines of code to : AppDelegate.swift file:
9-31
Flutter ™ Application Development
From your web browser, copy the first line of code: import Firebase
In your AppDelegate.swift file, add this line of code as illustrated in the following figure:
Then, copy the second line of code from your web browser which is:
FirebaseApp.configure()
9-32
Firebase AFD-200
It is recommended to run your app again in your IPhone emulator to be sure that
everything is configured right.
40- Open your web browser, and click Continue to Console. Now, you have finished:
Add Firebase to your iOS app configuration wizard and you should have the
following figure on your web browser which displays that you have configured
Firebase to your Android and iOS app.
Note: To get more information about add Firebase to your iOS project, check the
following web site: https://firebase.google.com/docs/ios/setup
Now, after configuring your Flutter app and Firebase to exchange data and services,
it is time to start using the Firebase services. The first Firebase service which you
will start using in this example is authentication as illustrated in the next section.
After a successful sign in, you can access the user’s basic profile information and
you can control the user’s access to data stored in other Firebase products. Also,
you can use the authentication tokens provided to verify the identity of users in your
own backend services.
9-33
Flutter ™ Application Development
By default, authenticated users can read and write data to the Firebase
Realtime Database and Cloud Firestore. You can control the access of those
users by modifying your Firebase Realtime Database and Cloud Storage
Security Rules.
Remember, the figure below explains how your Flutter app in this example works. In
the next step, you will configure the new_account.dart file Dart code to allow each
app user to create a new user account (user name & password) at your Firebase
Authentication web site.
To do that, you should add some Firebase plugins to your app as illustrated in the
next steps.
41- The Firebase settings are always updated; therefore, to be up to date, you
should follow the last setting in the following web link:
https://github.com/FirebaseExtended/flutterfire
If this link is not available , just type it on Google search, then you will get the last
updated link.
9-34
Firebase AFD-200
In this link, you will get all the information about the Firebase settings such as
authentication , database and others. Go to :
https://github.com/FirebaseExtended/flutterfire and scroll down, then you will get
the following figure:
Now, you should configure your app settings or add Firebase plug-in services to your
app by configuring: pubspec.yaml file for Firebase authentication and database.
Start with firebase_core because all the other packages depend on it. Click firebase_
core, then click Installing tab as illustrated in the following figure:
42- Copy the following dependencies value or the last updated value which you will find :
firebase_core: ^0.4.4
9-35
Flutter ™ Application Development
43- Open your pubspec.yaml file in your Android Studio and paste this value under
the dependencies as illustrated in the following figure:
44- Click Back on your web browser toolbar to get the “Available FlutterFire plugins:”
web page again or this web like: https://github.com/FirebaseExtended/flutterfire ,
then click: firebase_auth
45- Click the Installing tab, then copy the existing dependencies value:
firebase_auth: ^0.15.4
46- Paste this value in your pubspec.yaml file under the dependencies as illustrated
in the following figure:
47- Back on your web browser, to the “Available FlutterFire plugins:” web page or this
web link: https://github.com/FirebaseExtended/flutterfire , then click the :
firebase_database
48- Click the Installing tab, then copy the existing dependencies value:
firebase_database: ^3.1.1
49- Paste this value in your pubspec.yaml file under the dependencies as illustrated
in the following figure:
9-36
Firebase AFD-200
50- Back on your web browser to the “Available FlutterFire plugins:” web page or this
web link: https://github.com/FirebaseExtended/flutterfire , then click the :
cloud_firestore
51- Click the Installing tab, then copy the existing dependencies value:
cloud_firestore: ^0.13.3
52- Paste this value in your pubspec.yaml file under the dependencies as illustrated
in the following figure:
53- Now, at the top of the pubspec.yaml file content, click Packages Get to
incorporate all of those settings into your Flutter project.
54- Now, it is important to test your app running on your emulators; therefore, select
your Android emulator, stop your app, and then run it again.
Repeat the same thing for your IPhone emulator if you are using a Mac computer. If
not, skip this step and follow the next steps.
Note : (For Mac users only): If you are using an old version of CocoaPods, you are
recommended to update it to avoid any incompatibility problems in the last version
of Firebase packages. To do that, type the following command in Android Studio
terminal console:
9-37
Flutter ™ Application Development
After completing the installing the update, type the following command in the
terminal console: sudo gem install cocoapods
55- Now, it is the time to use Firebase authentication plug-in service in your app.
First, open the new_account.dart (New User Account Interface) and declare the
following three variables as illustrated in the following figure:
email : This variable represents the value which the app user will fill out in the email
address TextField in the new user app interface whose type is: String data type.
password: This variable represents the value which the app user will fill out in the
password TextField in the new user app interface. The Firebase authentication
password must be at least 6 characters and its type is: String data type.
_auth : This object is a static instance of the FirebaseAuth class and it represents
the app user name (email) and password. Here, you have initialized the _auth
Firebase instance which will be used later in creating and authenticating your Dart
code .
56- In new_account.dart file, configure the email and password variables as values
for these two TextField widgets (email address & password) as illustrated in the
following figures:
9-38
Firebase AFD-200
For Password:
9-39
Flutter ™ Application Development
Now, when the user taps the Create button, value 1 (email) & value 2 (password)
who will be sent to the Firebase authentication users list.
57- In new_account.dart file, add the following import package to your Dart code:
import ‘package:firebase_auth/firebase_auth.dart’;
58 - Open your Firebase web site again. On the left side of your web browser
under the Develop console, click Authentication. Then click Sign-in method tab as
illustrated in the following figure:
59 - Click Email/Password, click Enable switch button, then click Save as illustrated
in the following figure:
60 - Now, add the following code to the onPressed{} method which belongs to the
Create button to register the app user.
9-40
Firebase AFD-200
Explanation:
createUserWithEmailAndPassword Method:
This method contains the library: firebase_auth and class: FirebaseAuth. It tries to
create a new user account with the given email address and password.
async and await are keywords that work together. async can be placed before a
function, which always returns a result. async is used to invoke an asynchronous
code. While the keyword await works only inside async functions and it makes
Dart code wait until this data settles and returns the result. Here, in this example,
async performs asynchronous for creating the new user and await delays the
async until this process is completed.
try and catch are keywords that represent the handling of exceptions due to data
or coding errors during Dart program execution. A try block is the block of code in
which exceptions occur. A catch block catches and handles try block exceptions.
9-41
Flutter ™ Application Development
If statement
In this code, if the newUser has a value (not empty), this means that after creating
the new user account (email & password) on Firebase, the app user will move to
home.dart .
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('New Account '),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ListView(
shrinkWrap: true,
children: <Widget>[
Container(
alignment: Alignment.center,
child: Text('New User Account',
style: TextStyle(
fontSize: 40,
9-42
Firebase AFD-200
color: Colors.blue,
fontWeight: FontWeight.bold,
),
),
),
SizedBox(height: 10.0,),
Row(
children:[
Text('Email Address:',style: TextStyle(fontSize: 20.0),),
SizedBox(width: 20.0,),
SizedBox(width: 220.0,
child: TextField(onChanged: (value1) {email = value1;},
style: TextStyle(fontSize: 20, color: Colors.blue),
keyboardType: TextInputType.emailAddress,
// textInputAction: TextInputAction.done,
autocorrect: false,
cursorColor: Colors.red,
decoration: InputDecoration(
hintText: 'Your Email',
),
),
),
],
),
SizedBox(height: 10.0,),
SizedBox(width: 220.0,
child: TextField(
onChanged: (value2) {password = value2;},
// obscureText: true,
9-43
Flutter ™ Application Development
SizedBox(height: 10.0,),
Center(
child: Container(width: 100,
child: RaisedButton(color: Colors.blue,
child: Text("Create",
style: TextStyle(fontSize: 20, color: Colors.white),
),
onPressed: () async {
try {
final newUser =
await _auth.createUserWithEmailAndPassword(
email: email, password: password);
if (newUser != null) {
Navigator.pushNamed(context, 'Home');
}
} catch (e) {print(e);}
},
),
),
),
],
),
],
),
),
),
);
}
}
9-44
Firebase AFD-200
62- Run your app and click: New User Account button to move to the new_account.dart
interface.
63- Type your email address and any password (at least 6 characters) and tap the
Create button as illustrated in the following figure:
Important Note: In the login interface, don’t add a space before or after your email
address. Also, if you press the Tab key to move from the email address text filed to
enter the password login, there will be an extra space added to your email address.
This will cause an error message in your Android Studio run console such as :
(ERROR_INVALID_EMAIL, The email address is badly formatted., null).
The app user will be moved to the home.dart interface. In the next step, you
will configure the login.dart (Login interface) to use this user account (email &
password) which you created in the login process.
64- Back to your Firebase web site, in the Authentication part, click the Users tab.
You should find a new user account that has been created as illustrated in the
9-45
Flutter ™ Application Development
following figure:
65- Open login.dart file and import the following Firebase package:
import 'package:firebase_auth/firebase_auth.dart';
66- Configure the same previous two variables (email & password) and the _auth
Firebase instance as illustrated in the grey highlighted color in the following code:
String email;
String password;
final FirebaseAuth _auth = FirebaseAuth.instance;
@override
Widget build(BuildContext context) {
return MaterialApp(
child: TextField(
onChanged: (value1) {
email = value1;
},
9-46
Firebase AFD-200
child: TextField(
onChanged: (value2) {
password= value2;
},
68- Now to configure Login button to authenticate the app user credentials (email
& password), you should configure this button onPressed method in the same way
which you used to configure the user account creation step; however, here you will
use signInWithEmailAndPassword method in the login process as illustrated in
the following code:
child: RaisedButton(
color: Colors.blue,
child: Text("Login",
style: TextStyle(fontSize: 20, color: Colors.white),),
onPressed: () async {
try {
final User = await _auth.signInWithEmailAndPassword(
email: email, password: password);
if (User != null) {
Navigator.pushNamed(context, 'Service');
}
} catch (e) {
print(e);
}
},
),
69- Run your app, tap the Login button, enter the email and password which you
created on Firebase in the previous section, then tap the Login button. The app
user should login successfully, and the user will be moved to the service.dart app
interface as illustrated in the following figures:
9-47
Flutter ™ Application Development
If you login in at a different date of the user creation date, you should find the
Signed In field in the Users tab of Firebase authentication web page has the date of
the user’s sign in.
Logout Configuration
Now, after completing the login step successfully, the app user will get the service.
dart interface where all your app services are. Keep in mind, your app user will
expect to find a button or icon that has a logout action added to this service
interface. To add a logout icon to your Flutter app interface, perform the following
steps:
71- Import the Firebase authentication package to this file using the following
command at the top of the code :
import 'package:firebase_auth/firebase_auth.dart';
72- Declare the auth Firebase instance as illustrated in the grey highlighted color in
service.dart file :
9-48
Firebase AFD-200
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
73- Add to this file title bar a logout icon (exit_to_app ) by adding the following code:
IconButton(
icon: Icon(Icons.exit_to_app),
onPressed: () { },
),
]),
body: Center(
child: Container(
74- Run your app again, tap Login button, enter your user and password , then tap
Login. You should get the following icon in the service.dart interface:
9-49
Flutter ™ Application Development
75- Now, add the auth.signOut()method as an action to the icon onPressed() method.
Also, when the app user taps the logout icon, he/she will be moved to the previous interface
where this user was (login interface). The full code of service.dart follows:
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Android ATC Services'),
actions:<Widget>[
// action button
IconButton(
icon: Icon(Icons.exit_to_app),
onPressed: () {
auth.signOut();
Navigator.pop(context);
},
),
]),
body: Center(
child: Container(
child: Text('Welcome to Android ATC',
style: TextStyle(fontSize: 20.0,)),
),
),
),
);
}
}
9-50
Firebase AFD-200
76- Run your app again. Login to this service.dart interface using your user name
and password, which you have created at Firebase web site previously.
Now, before you tap the logout icon, open the Run console and focus on the messages
that will be generated when you tap this logout icon. Now, tap this logout icon. You will
logout of this interface and get the following messages in the Run console:
Also, you will be moved to the previous interface. But it does not end here as you
can see the login interface clearly still has the user name (email) and password .
You can make this password appear as (****) by adding the following property to
the password TextField in the login.dart as follows:
obscureText: true,
But, also when the user logs out form the service interface, he/she will find the
password value still existing.
77- The best design is removing the password which the app user typed in the
Password TextField after he/she taps the Login button. To do that , open login.
dart file, and add the grey highlighted part of the following code which declares the
object _controller using the TextEditingController class.
@override
Widget build(BuildContext context) {
9-51
Flutter ™ Application Development
78- In the login.dart, add the following grey highlighted part of the following code in
the password TextFiled widget :
Row(
children: [
Text('Password: ',
style: TextStyle(fontSize: 20.0),
),
SizedBox(
width: 20.0,
),
SizedBox(
width: 220.0,
child: TextField(
controller: _controller,
onChanged: (value2) {
password = value2;
},
79- In the login.dart, add the following grey highlighted part of the following code in
the onPress() method of the Login button :
child: RaisedButton(
color: Colors.blue,
child: Text("Login",
style: TextStyle(fontSize: 20, color: Colors.white),
),
onPressed: () async {
try {
final User = await _auth.signInWithEmailAndPassword(
email: email, password: password);
if (User != null) {
Navigator.pushNamed(context, 'Service');
_controller.clear();
}
9-52
Firebase AFD-200
} catch (e) {
print(e);
}
},
),
80- Now, run your app again, and test your Logout icon in the service.dart interface.
You will find that when you tap this icon, you be moved to the previous interface
(login.dart) and the password TextField is clear.
Firebase Database
Firebase offers two cloud-based, client-accessible database solutions that support
realtime data syncing:
a- Realtime Database: is Firebase›s original database. It›s an efficient, low-latency
solution for mobile apps that require synced states across clients in real-time.
9-53
Flutter ™ Application Development
•• Reads and writes from mobile SDKs •• Reads and writes from mobile SDKs
secured by Realtime Database secured by Cloud Firestore Security
Rules. Rules.
•• Reads and writes rules cascade. •• Reads and writes from server SDKs
secured by Identity and Access
•• Can validate data separately using Management (IAM).
the validate rule.
•• Rules don’t cascade unless you use
a wildcard.
9-54
Firebase AFD-200
Also, you downloaded your project Firebase JSON file : google-service.json, added it
to your project Android files and configured the Gradle files.
In addition, you configured your iOS directories of your Flutter project to have the
suitable configurations and files.
If you want to review these previous settings from the beginning, you will need to go
back to step 19 of this example.
Now, you will learn how to use the Firebase real time database in a Flutter project.
In this example, you will use this Firebase service in the service.dart file. To do that,
perform the following steps which will take you back to the previous steps:
81- Open service.dart file and import the Firebase database package by adding the
following code at the top of this file:
import 'package:firebase_database/firebase_database.dart';
82- Configure the body of this app to wrapped by Column widget, then wrap it using
Padding widget . The body code of service.dart will be as follows:
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Center(
child: Container(
child: Text('Welcome to Android ATC',
style: TextStyle(
fontSize: 20.0,
)),
),
),
9-55
Flutter ™ Application Development
],
),
),
),
);
}
}
To check the new configuration in the interface of services.dart file, no need to run
your app from the beginning, tap login and enter the user name & password to login
or open the service.dart file. Instead of that, just login one time and click the hot
reload button each time you want to check your new configurations.
83- Now, in this step add a Raised button widget to service.dart. You will use this
button onPressed method to save or send your app data to the Firebase database.
The code will be as follows:
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Center(
child: Text('Welcome to Android ATC',
style: TextStyle(
fontSize: 20.0,
),
),
),
SizedBox(height: 20.0),
RaisedButton(child: Text("Save"), onPressed:(){}),
],
),
),
),
);
}
}
9-56
Firebase AFD-200
84- Add a Firebase database instance to your project by adding the following code
to service.dart as illustrated in the grey highlighted color in the following code:
@override
Widget build(BuildContext context) {
85- Now, you will configure the function which will send or push your app database
values to Firebase database using push()and set() methods. In this example, you
may name this function: sendData (or any name) as illustrated in the following code:
sendData() {
databse.push().set(
{'Name': 'William', 'Country': 'USA', 'City': 'Denver'},
);
}
@override
9-57
Flutter ™ Application Development
86- Configure your app to call the sendData function when your app user taps the Save
Raised button by adding the following code to the onPressed method of this button :
87- Now, you should configure or enable your app Firebase database on Firebase
web site.
Open your browser , on the left side and as illustrated in the following figure, click
Database , then click Create database button.
9-58
Firebase AFD-200
89- In this step and as illustrated in the following figure, you should select where
you will host your database. Before you use Cloud Firestore, you must choose
a location for your database. To reduce latency and increase availability, store your
data close to the users and services that need it. For example, depending on my
location, I will select US-central. Click Done.
99- Now, as you see in the following figure, your database has been created and is
ready to receive your app data.
9-59
Flutter ™ Application Development
100- Change your database type to Realtime Database as illustrated in the following figure:
101- Now, back to your app, click hot Reload, then click Save button on service.dart file
Check your Android Studio Run console. You will find the following message: failed
DatabaseError: Permission denied as illustrated in the following figure:
Your app will try to send your data to Firebase real time database, but the default
security settings for any new Firebase database will deny read and write.
102- To change the security settings for your Firebase database, open your Firebase
web site, click Database, click Realtime Database, then click the Rules tab as
illustrated in the following figure:
9-60
Firebase AFD-200
As you see in this figure, the default rules disable read and write access to your
database by users. With these rules, you can only access the database through
the Firebase console.
It is essential that you configure these rules correctly before launching your app to
ensure that your users can only access data that they are supposed to.
During development, you can use the public rules in place of the default rules to set
your files publicly readable and writable. This can be useful for prototyping, as you
can get started without setting up Authentication. This level of access means that
anyone can read or write on your database. You should configure more secure rules
before launching your app.
103- Replace false with true for read and write rules as illustrated in the following
figure. Then, click Publish.
104- Now, back to your app and tap the Save button once.
9-61
Flutter ™ Application Development
105 - Check your Realtime database one Firebase web site. Your database should
be created and should look similar to the following figure:
If you expand your database, you will get your data as follows:
This format of database is the same JSON database format and if you click the
three vertical ellipsis button which is illistrated in the following figure, you will get a
submenu including export and import JSON options.
9-62
Firebase AFD-200
Cloud Firestore
One of the most common data structures is a database table. A database
table consists of columns (fields) and rows (records or values) as illustrated in the
table below:
In the cloud Firestore stores, data struacture is very similar to JSON tree as
collection of documents.
For example, the previous table will be stored in cloud Firestore as illustrated in the
following figure:
The container of data is called collection and the database may include one or more
collections (tables). The primary key or id for each record (row) is called document and
each document includes a group of field values that belong to the same document.
For example, in the previous database diagram, Alex is the value of the Name field and
Toronto is the value of City field. Also, all of these values belong to the same deocument
9-63
Flutter ™ Application Development
which is : 1
The document value can be auto and a random value or you can enter the values that
you want, but each document value must be a unique value in the same collection.
Now, you will continue using the same Flutter project (firebase_authentication) as
used previously. In the following part, you will create a cloud Firstore databse using
the same as your Firebase web account, create a new app interface (my_firestore.
dart file), and configure this app interface to retrieve or query your cloud firesore
data. To do that, perform the following steps:
106- At your Firebase web site, click Database on the left panel, then click Cloud Firestore.
107- Click Start collection to add the first Cloud Firestore, type customers for the
Collection ID (name), then click Next.
108- Now, you will add to your cloud Firestore collection (customers) its Documents
one by one to get the following data structure:
9-64
Firebase AFD-200
109 - For the first document, type Document ID: 1 , Name for the first field, Alex for
the first field value, then click the plus sign to add the second filed City type Toronto
for the second filed value, then click Save as illustrated in the following figure:
9-65
Flutter ™ Application Development
110 - Repeat the previous step three more times to add the remaining 3 Documents
to add the following data:
Now, you should create a new interface to retrieve or query the database which you
have created in your Cloud Firestore.
111- Right click lib folder, select New → Dart File. Type: my_firestore.dart for the file
name, then click OK.
107- Open the my_firestore.dart file, then add the following Scaffold code, import
the Firebase and Cloud Firestor libraries to create a simple Flutter app interface:
import 'package:flutter/material.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
9-66
Firebase AFD-200
To check how this interface looks like, go to home.dart file, and add a button to open
this interface.
108- First, add the navigation route name to your interface on main.dart.
Open main.dart file and add the following code at the top of its code:
import 'my_firestore.dart';
109- Open home.dart file to add the button which will open the file : my_firestore.dart .
RaisedButton(
color: Colors.blue,
child: Text('My Cloud Firestore',
style: TextStyle(fontSize: 20, color: Colors.white),
),
onPressed: () {
Navigator.pushNamed(context, 'Firestore');
},
),
9-67
Flutter ™ Application Development
110- Run your app. You should get the following figure:
Now, to connect your app with your Cloud Firestore you should use StreamBuilder
widget. This widget or class depends in its work on two classes, stream and
builder.
As illustrated in the following code, the StreamBuilder widget will listen to data
events flowing from the stream class, where the stream class provides a way to
receive a sequence of data events from your cloud Firestore collection (customers).
StreamBuilder (
stream:Firestore.instance.collection("customers").snapshots(),
builder:(context.snapshot){return ListView();}
)
When you set a listener (stream class), Cloud Firestore sends your listener an initial
snapshot of the data, and then another snapshot each time the document changes
(live update). This will be done using the snapshot function.
For every new data event, it will rebuild or update your app data, giving them the
latest data event to work with.
The best way to display your database on an app interface is using ListView widget.
9-68
Firebase AFD-200
111- Open my_firestore.dart file. Add the following code get the data from your
cloud Firestore and return it in a ListView widget. Remember here, your Cloud
Firestore collection is: customers.
stream: Firestore.instance.collection('customers').snapshots(),
112- Now, configure the widget function which will build your data in your app
interface. Add the following code below _MyCloudState and using ListTile widget
as illustrated in the following code:
9-69
Flutter ™ Application Development
title: Text(document["Name"]),
subtitle: Text(document["City"]),
);
}).toList();
}
Important note: here the name of the document fields are case sensitive.
113- Now use dataListWidget(snapshot) to display your data in the ListView widget as
illustrated in the grey highlighted code of the following full code of my_firestore.dart:
import 'package:flutter/material.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My Cloud Firestore'),
),
body: Container(
9-70
Firebase AFD-200
child: StreamBuilder(
stream: Firestore.instance.collection('customers').
snapshots(),
builder: (context, snapshot) {
return ListView(
children: dataListWidget(snapshot),
);
},
),
),
),
);
}
}
114- Click the hot reload button. You should get the following figure:
115- Back to your Cloud Firestore on Firebase web site, add a new document
including the following fields values :
Just check your phone emulator, no need to click Run or Hot Reload. You will find
this new data updated due to using snapshots function in StreamBuilder widget
in your code.
9-71
Flutter ™ Application Development
9-72
Firebase AFD-200
4- Type : lab_09 for Project Name, and create a new folder : Lab_09 for Project
Location. Click Next.
8- Click Get Started, then click Create a project. Fill out your project name “Lab 09”
or any other name as illustrated in the following figure. Check I accept the Firebase
terms, then click Continue.
9- Click Enable Google Analytics for this project to disable this feature because this
app is just for testing. Google features are important to get a report about your live
apps in the future.
9-73
Flutter ™ Application Development
Click Create Project. Then within seconds, you should get the following message as
illustrated in the following figure. It displays your project that has been created on
Google Firebase as illustrated in the following figure. Click Continue.
Now, your project has been created on Firebase web site and is ready to configure.
Lesson 9 includes how to add Firebase configuration to iOS and Android files in the
Flutter app step by step; however, in this lab you will configure only the Android part
only, and if you need more info about iOS, please review the content of the lesson.
10- To add Firebase configurations to your Android files, click on the Android icon in
the following figure:
9-74
Firebase AFD-200
11- You should get the following dialog box to register your app. As you will see, you
should enter your project name which must be a unique name on Google Play store.
To get your Android project name, go to Android Studio, then open the following path:
Then, scroll down the file content and as illustrated in the following figure, the
application Id is : com.androidatc.lab_09
9-75
Flutter ™ Application Development
Copy this Id and paste it on your Firebase web site for the Android package name.
Then click the Register app button.
12- Click Download google-service.json button to download the JSON configuration
file. Open your download folder and should find this file name : google-services.json
without any number.
13- Move this file : google-services.json from your download folder to the app
folder using the drag and drop technique. This app folder is in Android Studio in the
following path:
14- Now, return to the Firebase web site to complete the setup steps. Click Next.
15- In the Add Firebase SDK step, copy the line illustrated in the following figure or
click the copy icon.
16- Go to Android Studio, open the build.gradle file which is in the following path :
Paste this class path within the dependencies braces as illustrated in the following
figure:
9-76
Firebase AFD-200
17- Now, return to the Firebase web site and from the configuration wizard, copy the
other two lines :
go to Android Studio, open the build.gradle file which is in the following path:
Then, paste the other two lines as separate lines at the end of this file as illustrated
in the following figure:
Also, in the same build.gradle file add : multiDexEnabled true as illustrated in the
grey highlighted part of the following configuration:
9-77
Flutter ™ Application Development
defaultConfig {
applicationId "com.androidatc.lab_09"
minSdkVersion 16
targetSdkVersion 28
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
18- Return to the Firebase web site, click Next. Then click the Continue to console
button. You should get the following figure:
19- Now, close all your Gradle files. Be sure that your Android emulator is selected.
Stop your app, then run it again to be sure that all changes in your Android Studio
Gradle files were applied.
20- The Firebase settings and configurations are always updated. Therefore, to
be up to date, you should follow the last setting in the following web link: https://
github.com/FirebaseExtended/flutterfire
9-78
Firebase AFD-200
22- Now, you should configure your app settings or add Firebase plug-in services
to your app by configuring: pubspec.yaml file for Firebase authentication and
database.
Click the cloud_firestore plug-in , click the Installing tab and copy the dependencies
value : cloud_firestore: ^0.13.4 or the latest update value which you will find
at the time you perform this lab. The following figure displays the current cloud_
firestore configuration:
9-79
Flutter ™ Application Development
23- Open your pubspec.yaml file in your Android Studio and paste this value under
dependencies.
24- Click Back on your web browser toolbar to get the “Available FlutterFire plugins:”
web page again or go to the web link: https://github.com/FirebaseExtended/
flutterfire , then click the : firebase_auth , click the Installing tab , then copy the
existing dependencies value: firebase_auth: ^0.15.4
25- Paste this value in your pubspec.yaml file under the dependencies.
26- Back on your web browser to the “Available FlutterFire plugins:” web page or the web
link: https://github.com/FirebaseExtended/flutterfire, then click the : firebase_database
27- Click the Installing tab, then copy the existing dependencies value:
firebase_database: ^3.1.3
28- Paste this value in your pubspec.yaml file under the dependencies. The
dependencies of the pubspec.yaml file should be as illustrated in the following
figure:
29- Now, at the top of the pubspec.yaml file content, click Packages Get to
incorporate all of those settings into your Flutter project.
Now, you should create the Flutter app structure as illustrated in the following
figure, where the startup interface will be home.dart which includes two buttons:
The first button (New User Account), will forward the app user to (new_account.
dart) to create a new user account at Firebase web site. The second button (Login)
will forward the app user (login.dart) to login using the user name (email address)
and password which the app user has created in the “creating new user” step. If the
user can login successfully, he/she will login to the user profile (user_profile.dart)
interface to complete his/her profile by adding an image to his/her profile, and when
the app user clicks Save, all new information along with the image will upload to the
cloud Firestore database.
9-80
Firebase AFD-200
20- You should create three new interfaces (Dart files). Right click the lib folder
and select New → Dart File . Type home for the file name , and then press Enter (or
Return for Mac).
21- Repeat the previous step to create other three dart files: new_account.dart,
login.dart, and user_profile.dart
22- Open the new_account.dart file and create the interface which is illustrated in
the figure below. This interface contains two text fields to ask the app user to enter
his/her username and password. Then click the Create button.
9-81
Flutter ™ Application Development
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('New Account '),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ListView(
shrinkWrap: true,
children: <Widget>[
Container(
alignment: Alignment.center,
child: Text(
'New User Account',
style: TextStyle(fontSize: 40,
color: Colors.blue,
fontWeight: FontWeight.bold,),
),
),
SizedBox(height: 10.0,),
9-82
Firebase AFD-200
SizedBox(width: 220.0,
child: TextField(
onChanged: (value1) {
email = value1;},
Row(
children: [
Text('Password: ',
style: TextStyle(fontSize: 20.0),),
SizedBox(width: 20.0,),
SizedBox(width: 220.0,
child: TextField(
onChanged: (value2) {
password = value2;},
9-83
Flutter ™ Application Development
autocorrect: false,
),
),
],
),
SizedBox(height: 10.0,),
onPressed: () async {
try {
final newUser =await _auth.createUserWithEmailAndPassword(
email: email, password: password);
if (newUser != null) {
Navigator.pushNamed(context, 'Home');}}
catch (e) {
print(e);}
},
),
),
),
],
),
],
),
),
),
);
}
}
9-84
Firebase AFD-200
23- Open login.dart file and add the code which will create a login interface. The app
user will use this interface to login using the user name and password which he/she
has created in the create interface step. The login interface should be as illustrated
in the following figure:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
body: Padding(
9-85
Flutter ™ Application Development
SizedBox(height: 10.0,),
SizedBox(width: 20.0),
SizedBox(width: 220.0,
child: TextField(
onChanged: (value1) {
email = value1;},
9-86
Firebase AFD-200
),
],
),
SizedBox(height: 10.0,),
SizedBox(width: 20.0,),
SizedBox(width: 220.0,
child: TextField(
controller: _controller,
onChanged: (value2) {
password = value2;},
style: TextStyle(fontSize: 20, color: Colors.blue),
textInputAction: TextInputAction.done,
autocorrect: false,
),
),
],
),
SizedBox(height: 10.0,),
onPressed: () async {
try {
9-87
Flutter ™ Application Development
Now, you should design the interface which includes the services that the user
logged in for. Remember, the purpose of this lab is to practice configuring login
and logout of an app interface. Here, we will not focus on the services the user will
find after login because there are many services that can be added here, such as
creating a user profile, shopping, payment, subscription and others.
24- To create this app interface, open the user_profile.dart file and type the following
code:
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
9-88
Firebase AFD-200
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('User Profile'),
actions: <Widget>[
// action button
IconButton(
icon: Icon(Icons.exit_to_app),
onPressed: () {
auth.signOut();
Navigator.pop(context);},),]),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Center(
child: Text('Welcome to Android ATC',
style: TextStyle(
fontSize: 20.0,),),),
SizedBox(height: 20.0),
],
),
),
),
);
}
}
25- Open home.dart file and add the following code which creates the startup
interface, which has the navigation buttons to all app interfaces:
9-89
Flutter ™ Application Development
import 'package:flutter/material.dart';
RaisedButton(
color: Colors.blue,
child: Text('Login',
style: TextStyle(fontSize: 20, color: Colors.white),
),
onPressed: () {
Navigator.pushNamed(context, 'Login');},
),
],
),
9-90
Firebase AFD-200
),
),
);
}
}
25- Open main.dart file, delete all the code and add the following code which makes
the home.dart file interface the start up interface when you run this app. This file
includes all the route navigation:
import 'login.dart';
import 'new_account.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'home.dart';
import 'user_profile.dart';
routes: {
'Login': (context) => Login(),
'NewAccount': (context) => NewAccount(),
'Profile': (context) => Profile(),
'Home': (context) => Home(),
},
);
}
}
9-91
Flutter ™ Application Development
26- Before creating any user account on Firebase, you should open your Firebase web
site again and on the left side of your web browser under the Develop console, click
Authentication. Then click the Sign-in method tab as illustrated in the following figure:
27 - Click Email/Password, click the Enable switch button, then click Save as
illustrated in the following figure:
28- Stop your emulator, click Run your app, then click : New User Account button to
move to the new_account.dart interface.
Important Note: In the login or create the user account interface, make sure not
to add a space before or after your email address. Also, don’t press the Tab key to
move from the email address text field to the password login since there will be an
extra space (extra character) added to your email address. This extra character will
result in an error message in your Android Studio run console such as : (ERROR_
INVALID_EMAIL, the email address is badly formatted., null).
Type your email address and any password (at least 6 characters), then tap the
Create button as illustrated in the following figure:
9-92
Firebase AFD-200
29- Back to your Firebase web site , and in the Authentication part, click the Users
tab where you should find that there is a new user account that has been created as
illustrated in the following figure:
30- Tap the Login button. Enter the user name (email) and the password for the
account which you have created in the previous step (without pressing Tab key
when you move from the email address Text Field to the Password Text Field), then
tap the Login button as illustrated in the following figure:
9-93
Flutter ™ Application Development
You will get to the content of the user_profile.dart file as illustrated in the following figure:
31- In the right corner of the title bar of the user_profile.dart interface, tap the exit
icon to logout of this interface. Then you will go back to the Login interface.
This is the end of the lab. However, please note the following:
I- The explanation of all the previous steps is available in the example of this lesson.
II- Try to complete this lab by adding an extra part to create a user profile interface.
For example, try to add an image to the Firebase storage or add the user information
such as full name and address to the cloud Firestore.
III- You may use the lab source files to import these lab files to your Android Studio IDE,
and test how this lab works, but you should configure your Firebase web account to be
compatible with this lab code. Also, add your Firebase google-services.json file to your
Android Studio app folder instead of the existing file.
9-94
GPS and Google Maps AFD-200
Introduction............................................................................................................................ 10-2
What is GPS and how does it work?..................................................................................... 10-2
The Camera Position.............................................................................................................. 10-4
Adding Google Maps to a Flutter app................................................................................... 10-5
Getting a Google API key.................................................................................................. 10-6
Adding Google Maps Flutter plug-in as a dependency................................................... 10-11
Adding your API key for your Android app....................................................................... 10-12
Adding your API key for your iOS app.............................................................................. 10-13
Adding a Google Map on Your Flutter App Screen.......................................................... 10-14
Adding a Google Map Marker........................................................................................... 10-18
Google Map Types............................................................................................................. 10-21
Moving the Camera (Camera Animation)........................................................................ 10-23
Capturing an App User’s Location for iOS and Android Apps......................................... 10-26
Lab10: Location-Aware Apps Using GPS and Google Maps............................................... 10-27
Getting a Google API key.................................................................................................. 10-28
Creating an App Interface................................................................................................. 10-33
Configuring your App to Use Your API Key...................................................................... 10-34
Adding a Google Map on your Flutter App Screen.......................................................... 10-36
Adding a Google Map Marker........................................................................................... 10-38
Capturing Users’ Location................................................................................................ 10-39
Configuring User App’s Permission.................................................................................. 10-41
10-1
Flutter ™ Application Development
Introduction
Most of the mobile applications nowadays rely on users’ Geo-location and web mapping
services. GPS is considered one of the most accurate Geo-location providers. In order to
increase users’ experience of location awareness, geo-coordinates should be represented
graphically and this can be achieved using web-mapping services such as Google Maps.
For example, open Google maps: google.com/maps web site, then check your home
address on Google maps.
The following figure displays the Latitude and Longitude values as follows:
Latitude: 43.588160
Longitude: -79.643124
10-2
GPS and Google Maps AFD-200
The GPS Coordinates depend on the latitude and longitude values. Latitude and
Longitude are the units that represent the coordinates in a geographic coordinate
system. Just like every actual house has an address (which includes the number,
the name of the street, the city, etc ), every single point on the surface of earth can
be specified by latitude and longitude coordinates. Therefore, using latitude and
longitude, you can specify virtually any point on earth.
As a Flutter developer, you can use the Geo-location term which is an identification
or estimation of the real-world geographic location of an object, such as a radar
source, mobile phone, or Internet-connected computer terminal. In its simplest form,
a geo-location involves the generation of a set of geographic coordinates (Latitude
and Longitude) and is closely related to the use of positioning systems.
The connection between a GPS satellite and receivers (such as smart devices)
is a one-way connection; receivers don’t send any information to satellites. The
connection works through the use of a procedure called Trilateration.
There are various types of navigational satellite systems. The most important one is
NAVSTAR, which is basically used in all mobile devices. In NAVSTAR system, every
single point on Earth is covered by at least four GPS satellites, which is enough to
calculate the device geo-location coordinates.
10-3
Flutter ™ Application Development
As mentioned before, GPS is one of the most accurate geo-location systems. It has
accuracy between 7.8~3 meters.
The Android and iOS system provides a reliable API that helps developers capture
the user’s coordinates using the GPS and other location service providers, which will
be listed in the next topic.
The map view is modeled as a camera looking down on a flat plane. The position
of the camera (and hence the rendering of the map) is specified by the following
properties: target (latitude/longitude location), bearing, tilt, and zoom. You will use these
camera attributes later in this lesson to control the camera position or motion.
Target (location)
The camera target is the location of the center of the map, specified as latitude and
longitude co-ordinates.
10-4
GPS and Google Maps AFD-200
Bearing (orientation)
The camera bearing is the direction in which a vertical line on the map points,
measured in degrees clockwise from the north. Someone driving a car often turns
a road map to align it with their direction of travel, while hikers use a map and a
compass usually to orient the map so that a vertical line points north. The Maps API
lets you change a map’s alignment or bearing. In the “moving the camera” topic of
this lesson, you will add this attribute to the map camera position and see how its
value affects in changing the camera direction.
The tilt defines the camera’s position on an arc between directly over the
map’s center position and the surface of the Earth, measured in degrees from
the nadir (the direction pointing directly below the camera). When you change the
viewing angle, the map appears in perspective, with far-away features appearing
smaller, and nearby features appearing larger. In the “moving the camera” topic of
this lesson, you will add this attribute to the map camera position and see how its
value effects in changing the camera position.
Zoom
The zoom level of the camera determines the scale of the map. At larger zoom
levels, more detail can be seen on the screen, while at smaller zoom levels more of
the world can be seen on the screen. At zoom level 0, the scale of the map is such
that the entire world has a width of approximately 256 dpi (density-independent
pixels).
The Google Maps Flutter API lets you display a Google map in your Flutter
application. The maps are similar to those you see on Google Maps for mobile apps,
and the API exposes many of the same features. With the Google Maps Flutter
plug-in, you can add maps based on Google maps data to your application. The
plug-in automatically handles access to the Google Maps servers, map display, and
response to user gestures such as clicks and drags. You can also add markers to
your map. These objects provide additional information for map locations, and allow
the user to interact with the map.
10-5
Flutter ™ Application Development
Example:
In the following example, you are going to create a new Flutter project that includes a Google
map. In this project, you are going to learn about the classes and methods which are used
to add and configure a Google map in Flutter applications (Android & iOS) and you will also
learn how to determine a specific location on the map (add a marker).
7- Select your country, click I Agree , then click AGREE AND CONTINUE
10-6
GPS and Google Maps AFD-200
8- In the next step in getting an API key, you should add your project to Google Cloud
Platform. To do that, click the Select a project drop down list, then you will get the
following figure. Click NEW PROJECT
9- As illustrated in the following figure, enter your project name. For our example, we
used : myfirst-flutter-api, you may type what you want as a project name. Click CREATE
10-7
Flutter ™ Application Development
11- Click your project name : myfirst-flutter-api as illustrated in the following figure:
10-8
GPS and Google Maps AFD-200
13- Click “+ CREATE CREDENTIALS”, then select: API Key as illustrated in the following figure:
14- You will get the following dialog box which includes your API key. Copy your API
key in a safe location (in a separate Notepad or text file) because you will use it later
in your Flutter app configurations within the next steps. Click CLOSE.
15- Now, to enable Maps SDK for iOS and Android click:
Google Cloud Platform → APIs & Services → Library as illustrated in the following
figure:
10-9
Flutter ™ Application Development
16- Here, as illustrated in the following figure, click Maps SDK for Android
10-10
GPS and Google Maps AFD-200
17- Click: Google Cloud Platform → APIs & Services → Library, click Maps SDK for
iOS, then click Enable
Now, the Maps SDK for Android and iOS has been enabled.
This was the last step in configuring your Google Cloud Platform. Now, your Google
maps service is ready to exchange the information with your iOS and Android app
using your API Key.
google_maps_flutter: ^0.5.24+1
Go back to your Flutter app and open the pubspec.yaml file, then add this
dependency value as illustrated in the following figure:
10-11
Flutter ™ Application Development
Then, click Packages get to update the new configuration in pubspec.yaml file. You
should not have any error in the Message console. The following figure displays that
everything works fine after clicking the Packages get:
Note: Now, you can use the following command in your Dart command:
import 'package:google_maps_flutter/google_maps_flutter.dart';
Then, add only the grey highlighted part of the following code in the application
tag. Here, use your API key which you have generated on the Google cloud console
instead of in this example.
<application
android:name="io.flutter.app.FlutterApplication"
android:label="googlemap1"
android:icon="@mipmap/ic_launcher">
<meta-data android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyBu8jtYmJyL9FCsG_L2r9sbldoT7oKFoQ4"/>
<activity
10-12
GPS and Google Maps AFD-200
Make two changes in this file. First, add an import statement to pull in
the Google Maps headers, then call the provideAPIKey() method of
the GMSServices singleton. This API key enables Google Maps to correctly serve
map tiles. To do that, perform the following steps:
Add only the grey highlighted code to this file and use your API key instead, which
you have in this example:
import UIKit
import Flutter
import GoogleMaps
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication
LaunchOptionsKey: Any]?
) -> Bool {
GMSServices.provideAPIKey("AIzaSyCxx9mt38hxcFK_ZzR2xDQzw0t7mG9lEJQ")
GeneratedPluginRegistrant.register(with: self)
return super.application(application,
didFinishLaunchingWithOptions: launchOptions)
}
}
10-13
Flutter ™ Application Development
Open the following file: ios → Runner → Info.plist , then add only two grey
highlighted lines of code to the Info.plist file as illustrated in the following code:
In this step, you will configure your app interface to display the Google map using
GoogleMap() widget.
Before adding the code which will add the Google map to your app interface, check
the following details which help in understanding the classes and methods that you
need to use in adding GoogleMap widget to your app widget tree.
To add Google map to your app interface, you should use the GoogleMap widget or
class. This is the main class of Google Maps SDK for Android and iOS apps and is
the entry point for all methods related to the map. The following code is an example
of using GoogleMap widget:
10-14
GPS and Google Maps AFD-200
GoogleMap(
onMapCreated: _myMapCreated,
GoogleMapController mapController;
You can adjust the viewpoint of a map by changing the position of the camera (as opposed
to moving the map). You may use the map’s camera to set parameters such as location,
zoom level, tilt angle, and bearing. In the previous code of the GoogleMap widget, we used
the following configuration to determine the position on the Google map.
_location function should be declared before using the GoogleMap widget as follows:
LatLng is a public final class (immutable class) representing a pair of latitude and
longitude coordinates.
The zoom value in the CameraPosition class represents the zoom level of the map
( zoom in or out ).
10-15
Flutter ™ Application Development
22- You can now add a GoogleMap widget to your widget tree. Open main.dart file,
delete all code, then add the following code:
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
GoogleMapController mapController;
void _myMapCreated(GoogleMapController controller) {
mapController = controller;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Maps Sample App'),
),
body: GoogleMap(
onMapCreated: _myMapCreated,
initialCameraPosition: CameraPosition(target:_location,
zoom:13.0),
),
),
);
}
}
10-16
GPS and Google Maps AFD-200
23- Run your app. You should get the following figure:
Note: Depending on your emulator type and settings, you may get a message asking
you to update Google Play services before getting the Google map as illustrated in
the following figure. Click this UPDATE button, following the next steps, and then
your emulator will work fine.
If you make any changes in your code, before running your app to see the new
Google map configurations, stop your app and run it again.
10-17
Flutter ™ Application Development
In this topic you will add a marker (pin) to your map to display the location you
want. In this example by using the same previous code, you are going to add a map
marker for Toronto CN tower in Toronto, Canada. You must have the latitude and
longitude for this location to add it to your Google map. To get the latitude and
longitude coordinates for any location, you can simply go to www.google.com/
maps web site and type the address you want, to know its latitude and longitude
coordinates. In this example, just type Toronto CN tower, then press Enter (or Return
for Mac). You will get the following figure:
To get this address latitude and longitude coordinates, right click the marker as
illustrated below, then select → What’s here?
10-18
GPS and Google Maps AFD-200
Also, you can go to the address bar of your web browser and copy the values that
come after the @ sign. The first value is the latitude and the second value is the
longitude as illustrated in the following figure:
24- Copy the latitude and longitude values from your web address bar, then use
these values in the previous code as follows:
Then, stop and run your app again. You will get the following run output:
10-19
Flutter ™ Application Development
There are a lot of web sites that provide free location services, all you need to
do is type the address and you will get the latitude and longitude coordinates.
Important Note: If you want to know all the methods and configurations you may
use with GoogleMap class, hold Ctrl key (or command key for Mac), then click the
GoogleMap widget in your code. Another tab will open including google_map.dart file
content. You may use these methods in your app with this widget. You may use the
same technique with all other Flutter widgets to know which methods you may use.
25- If you are creating an app for a restaurant or another company which has many
branches, and you want to display these branches on your app Google map, you
should create and add a marker for each branch, then add them to your app Google
map widget. Therefore, it is a good idea to organize your app code by creating a
separate Dart file including all the markers which you want to add to your app map,
then call these markers to your app interface.
Type: MapMarkers for the file name and then press Enter.
26- Open MapMarkers.dart file, then add the following code which is related to
creating the Marker class for Toronto CN tower:
import 'package:google_maps_flutter/google_maps_flutter.dart';
27- Now, open main.dart file and add at the top of this file the following:
import 'MapMarkers.dart';
10-20
GPS and Google Maps AFD-200
Then, add the cnTowerkarker maker to your GoogleMap widget as illustrated in the
grey highlighted part of the following code:
body: GoogleMap(
markers: {cnTowerkarker},
onMapCreated: _myMapCreated,
initialCameraPosition: CameraPosition(target: _location, zoom:13.0),
),
28- Stop your app and run it again. You should get the following run output:
If you click the marker (pin), you will get the marker title value: Toronto Tower.
There are about five types of Google maps available to configure with GoogleMap
widgets. These are as follows:
Normal: It is the default value that you get when you run your app in the last time.
10-21
Flutter ™ Application Development
body: GoogleMap(
mapType: MapType.hybrid,
markers: {cnTowerkarker},
onMapCreated: _myMapCreated,
initialCameraPosition: CameraPosition(target: _location, zoom:13.0),
),
30- Stop your app and run it again. The run output follows:
Try other types of maps to understand how each one looks like.
10-22
GPS and Google Maps AFD-200
The Maps API allows you to change which part of the world is visible on the map. This is
achieved by changing the position of the camera (as opposed to moving the map).
When you change the camera, you have the option of animating the resulting
camera movement. The animation interpolates between the current camera
attributes and the new camera attributes.
This will add some interactivity to your Google map. For example, when you
add a floating action button or icon to your app map and when the app user
taps this button or icon, the camera position will be moved from the current
position to a specific location. To do that, you should add and configure the
GoogleMapController class in your app as you will see in this topic.
Use the same code as used previously and add a floating button to your current
map. When the app user taps this button, the camera position will be moved from
the current coordinates (Toronto) to Niagara Falls ( this location is on the border
between Ontario, Canada and the American state of New York ). If you want to get
the new location coordinates, open Google maps and find its coordinates. Niagara
Falls (new location) coordinates are :
Latitude: 43.0807790 and Longitude: 79.0785500
Also, you should add a flat action button to your interface. When the app user taps this
button, he/she will call gotoNiagaraFalls function. The flat action button code follows:
10-23
Flutter ™ Application Development
floatingActionButton: FloatingActionButton.extended(
onPressed: gotoNiagaraFalls,
label: Text('To Niagara Falls!'),
icon: Icon(Icons.directions_boat),
),
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'MapMarkers.dart';
GoogleMapController mapController;
void _myMapCreated(GoogleMapController controller) {
mapController = controller;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Maps Sample App'),
),
body: GoogleMap(
10-24
GPS and Google Maps AFD-200
markers: {cnTowerkarker},
onMapCreated: _myMapCreated,
initialCameraPosition: CameraPosition(target: _location, zoom:13.0),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: gotoNiagaraFalls,
label: Text('To Niagara Falls!'),
icon: Icon(Icons.directions_boat),
),
),
);
}
32- Stop your app and run it again. When you tap the To Niagara Falls button, your
map camera position will be moved to Niagara Falls map.
33- Add to the current CameraPosition class the following grey highlighted
attributes (bearing & lilt) which will add the type of camera animation when your
camera position moves from the current location (Toronto) to Niagara Falls.
10-25
Flutter ™ Application Development
Stop your app , run it again ,and click the button: To Niagara Falls. Now, you have
added an animation effect to your camera motion.
Flutter SDK provides a simplified way to implement both a GPS and a Network
provider. This topic explains how to implement both providers and which provider is
more suitable for the application.
Capturing a user’s location is a time consuming process especially when using a GPS.
Moreover, capturing any location is not allowed to be executed on Main thread or it
will be blocked by the operating system. Surely, this will lead to creating a new thread.
Flutter SDK will handle the way of capturing coordinates using a thread creation.
You can get the app user’s location on Google map if you use the Flutter Geo-locator
Plug-in which is available at: https://pub.dev/packages/geolocator#-readme-tab-
A Flutter Geo-location plug-in which provides easy access to the platform specific
location services. This plug-in has the following features:
•• Get the current location of the device.
•• Get the last known location.
•• Get continuous location updates.
•• Check if location services are enabled on the device.
•• Translate an address to geo-coordinates and vice verse (a.k.a. Geo-coding);
•• Calculate the distance (in meters) between two geo-coordinates.
•• Check the availability of Google Play services (on Android only).
The lab of this lesson includes how to configure your Flutter app (iOS & Android) step
by step to capture the app user’s location (coordinates) on Google map.
10-26
GPS and Google Maps AFD-200
If you find any step of this lab unclear, please go back to the lesson where you will
find everything in detail. Also, the lab source code files include the files of this lab. It
is important to create this lab step by step to obtain the maximum benefits.
10-27
Flutter ™ Application Development
4- In the next step for getting an API key, you should add your project to Google
Cloud Platform. To do that, click the Select a project drop down list, then you will get
the following figure. Click NEW PROJECT
10-28
GPS and Google Maps AFD-200
5- As illustrated in the following figure, type your project name. For our example, we
used : myfirst-flutter-api, you may type what you want as a project name. Click CREATE
10-29
Flutter ™ Application Development
8- As illustrated in the following figure, click the Google Cloud Platform menu →
API & Services → Credentials.
10-30
GPS and Google Maps AFD-200
10- Then, you will get the following dialog box which includes your API key. Copy
your API key in a safe location (in a separate Notepad or text file) because you will
use it later in your Flutter app configurations in the next steps. Click CLOSE.
11- Now, to enable Maps SDK for iOS and Android click: Google Cloud Platform →
APIs & Services → Library as illustrated in the following figure:
10-31
Flutter ™ Application Development
12- Here, as illustrated in the following figure, click Maps SDK for Android
13- Click: Google Cloud Platform → APIs & Services → Library, click Maps SDK for
iOS, then click Enable
Now, the Maps SDK for Android and iOS has been enabled.
10-32
GPS and Google Maps AFD-200
16- Type: lab_10 for Project Name, and create a new folder: Lab_10 for Project
Location. Click Next.
18- To get the last Google maps plug-in dependency configurations, go to the
following web site:
google_maps_flutter: ^0.5.24+1
Then go back to your Flutter app and open the pubspec.yaml file which is the location
in the following path : lab_10 → pubspec.yaml , as illustrated in the following figure:
10-33
Flutter ™ Application Development
19- Click Packages get to update the new configuration in pubspec.yaml file. You
should not have any error in your Android Studio Message console.
Then, add only the grey highlighted part of the following code in the application
tag. Here, use your API key which you have generated on Google cloud console
instead of the one in this lab.
<application
android:name="io.flutter.app.FlutterApplication"
android:label="googlemap1"
android:icon="@mipmap/ic_launcher">
<meta-data android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyBu8jtYmJyL9FCsG_L2r9sbldoT7oKFoQ4"/>
<activity
21- Click File → Save ALL and close the AndroidManifest.xml file.
22- Unlike Android, adding an API key on iOS requires changes to the source code of
the Runner app. Open AppDelegate.swift file which is in the following path:
Make two changes in this file. First, add an import statement to pull in the
Google Maps headers, and then call the provideAPIKey() method from
the GMSServices singleton. This API key enables Google Maps to correctly serve
map tiles. To do that, perform the following steps:
Add the grey highlighted code to this file and use your API key instead of which you
have in this lab:
10-34
GPS and Google Maps AFD-200
import UIKit
import Flutter
import GoogleMaps
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.
LaunchOptionsKey: Any]?
) -> Bool {
GMSServices.provideAPIKey("AIzaSyCxx9mt38hxcFK_ZzR2xDQzw0t7mG9lEJQ")
GeneratedPluginRegistrant.register(with: self)
return super.application(application,
didFinishLaunchingWithOptions: launchOptions)
}
}
Open the following file: ios → Runner → Info.plist , and then to this file, add the
only two grey highlighted lines of code to the Info.plist file as illustrated in the
following code:
10-35
Flutter ™ Application Development
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
In this step, you will configure your app interface to display the Google map using
GoogleMap() widget.
24- To add a GoogleMap widget to your widget tree. Open main.dart file, delete all
code and add the following code:
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
GoogleMapController mapController;
void _myMapCreated(GoogleMapController controller) {
mapController = controller;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Maps Sample App'),
10-36
GPS and Google Maps AFD-200
),
body: GoogleMap(
onMapCreated: _myMapCreated,
initialCameraPosition: CameraPosition(target:_location, zoom:13.0),
),
),
);
}
}
25- Run your app. You should get the following figure:
Note: Depending on your emulator type and settings, you may get a message asking
you to update Google Play services before getting Google map as illustrated in
the following figure. Click this UPDATE button, following the next steps and your
emulator will be working fine.
10-37
Flutter ™ Application Development
Note: If you make any changes in your code, before you run your app to see the new
Google map configurations, stop your app, and then run it again.
You will create a separate Dart file to configure the map marker.
26 - Right click lib folder, and then select New → Dart File
27- Open MapMarkers.dart file, then add the following code which is related to
create the Marker class for Toronto CN tower:
import 'package:google_maps_flutter/google_maps_flutter.dart';
28- Now, open main.dart file and add the following line of code at the top of this file:
import 'MapMarkers.dart';
Then, add the cnTowerkarker maker to your GoogleMap widget as illustrated in the
grey highlighted part of the following code:
10-38
GPS and Google Maps AFD-200
body: GoogleMap(
markers: {cnTowerkarker},
onMapCreated: _myMapCreated,
initialCameraPosition: CameraPosition(target: _location, zoom:13.0),
),
29- Stop your app and run it again. You should get the following run output:
If you click the red marker (red pin), you will get the marker title value: Toronto Tower.
30- To add the Flutter Geolocator plug-in to your app and use all its libraries, add the
geolocator as a dependency in your pubspec.yaml file as illustrated in the following figure:
31- To enable Geolocation plug-in for Android devices, upgrade Android Gradle by
open the following file:
android → gradle.properties
Be sure that you have the following settings in your gradle.properties file.
android.useAndroidX=true
android.enableJetifier=true
10-39
Flutter ™ Application Development
If Not , add them. The file should have the following settings:
Make sure that the SDK version is at least 28, as illustrated in the following figure:
Note: If your SDK version is less than 28, you cannot just replace it here in build.
gradle file with value 28. You must install at least Android SDK API level 28. To
do that, in your Android Studio, click File → Settings, then go to: Appearance &
Behavior → System Settings → Android SDK in the Settings dialog box. Check in
the right side the SDK Platforms as illustrated in the following figure and install at
least Android 9.0 if you don’t have it.
10-40
GPS and Google Maps AFD-200
You should add these configurations to your Android and iOS code to ask your app
user for permission to turn on the Location feature on his/her device to get the app
user location coordinates.
Then, add the following line as a direct child of the <manifest> tag:
The grey highlighted part of the following AndroidManifest.xml file displays exactly
where you should add this location permission code:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.androidatc.googlemap">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
...
...
10-41
Flutter ™ Application Development
34 - To configure the permission on iOS devices, open the Info.plist file which is located
in the following path: ios → Runner → Info.plist , then add the following code:
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location when open.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs access to location when in the background.</
string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs access to location when open and in the
background.</string>
The following figure displays where you should add the previous code in Info.plist file:
35- Open main.dart file. You should import the geolocator package; therefore, add
the following code at the top of the main.dart file.
import 'package:geolocator/geolocator.dart';
10-42
GPS and Google Maps AFD-200
To run this function, you should add a Floating action button. When the app user
clicks the button, he/she will be moved to his/her location.
If you have any question about the next code, review the “Moving the Camera” topic
in this lesson.
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'MapMarkers.dart';
import 'package:geolocator/geolocator.dart';
GoogleMapController mapController;
void _myMapCreated(GoogleMapController controller) {
mapController = controller;
}
setState(() async {
final GoogleMapController controller = await mapController;
10-43
Flutter ™ Application Development
controller.animateCamera(
CameraUpdate.newCameraPosition(MyLocation),
);
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Maps Sample App'),
),
body: GoogleMap(
markers: {cnTowerkarker},
onMapCreated: _myMapCreated,
initialCameraPosition: CameraPosition(target: _location, zoom:13.0),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: getCurrentLocation,
label: Text('To My Location'),
icon: Icon(Icons.directions_boat),
),
),
);
}
}
37- Before running your app, remember that you are working with a virtual device
(emulator); therefore, configure your location (latitude and longitude) manually by
clicking the more button of the virtual device tools bar (See illustration below), then
select you location on the map (for example select your home address). In this lab, I
selected San Francisco city in California and Click SET LOCATION.
10-44
GPS and Google Maps AFD-200
38- Run your app. You should get the following message asking for permission to
have your coordinates for the first run time only.
Click Allow. Then, when you get your map as illustrated in the following figures, tap the
button : To My Location, your map camera will move to your location which you set on
this emulator. In the following figure, the map camera has moved to San Francisco.
10-45
Flutter ™ Application Development
10-46
App Testing & Publishing AFD-200
11-1
Flutter ™ Application Development
Testing the released version of your application helps to ensure that your application
runs properly under realistic device and network conditions. Ideally, you should test your
application on at least one handset-sized device and one tablet-sized device to verify that
your user interface elements are sized correctly and that your application’s performance
and battery efficiency are acceptable.
Android and iOS users expect high-quality apps. App quality directly influences the long-
term success of an app—in terms of installs, users’ ratings and reviews, engagement,
and user retention.
You should assess the core aspects of quality in your app, through a compact set
of quality criteria and associated tests. All Android and iOS apps should meet these
criteria.
Before publishing your apps, test them against these criteria to ensure that they
function well on many devices, meet Android and iOS standards for navigation and
design, and are prepared for promotional opportunities in the Google Play store and
Apple App store.
11-2
App Testing & Publishing AFD-200
a- The app does not redefine the expected function of a system icon (such as the
Back button).
b- The app does not replace a system icon with a completely different icon if it
triggers the standard user interface behavior.
c- If the app provides a customized version of a standard system icon, the icon
strongly resembles the system icon and triggers the standard system behavior.
d- The app does not redefine or misuse Android or iOS UI (user interface) patterns,
such that icons or behaviors could be misleading or confusing to users.
If a screen is the topmost one in an app (that is, the app’s home), it should not
present an Up button.
11-3
Flutter ™ Application Development
The system Back button is used to navigate, in reverse chronological order, through
the history of screens the user has recently worked with. It is generally based on the
temporal relationships between screens, rather than the app’s hierarchy.
When the previously viewed screen is also the hierarchical parent of the current
screen, pressing the Back button has the same result as pressing an Up button
which is a common occurrence. However, unlike the Up button, which ensures that
the user remains within your app, the Back button can take the user back to the
Home screen, or even to a different app.
All workflow diagrams are dismissible using the Back button and pressing the Home
button at any point navigates to the Home screen of the device.
f- The app uses notifications only to indicate a change in context related to the user
personally (such as an incoming message), or exposes information/controls related
to an ongoing event (such as music playback or a phone call).
2- Functionality
These criteria ensure that your app provides the expected functional behavior.
a- The app requests only the absolute minimum permissions that it needs to
support core functionality.
b- The app does not seek permissions to access sensitive data (such as Contacts
or the System Log) or services that can cost the user money (such as the Dialer or
SMS), unless related to a core capability of the app.
d- Audio does not play when the screen is off, unless this is a core feature (for
11-4
App Testing & Publishing AFD-200
e- Audio does not play behind the lock screen, unless this is a core feature.
f- Audio does not play on the home screen or over another app, unless this is a core
feature.
g- Audio resumes when the app returns to the foreground, or there’s what indicates
to the user that playback is in a paused state.
h- The app supports both landscape and portrait orientations (if possible). Minor
changes in content or views are acceptable.
i- The app uses the whole screen in both orientations and does not letterbox to
account for orientation changes.
j- The app correctly handles rapid transitions between display orientations without
rendering problems.
k- The app should not leave any service running when the app is in the background,
unless related to a core capability of the app.
For example, the app should not leave services running to maintain a network
connection for notifications, to maintain a Bluetooth connection, or to keep the GPS
powered-on.
l- When the app resumes from the recent app switcher, the app returns the user to
the exact state in which it was when last used.
m- When the app resumes after the device wakes from a state of sleep (locked), the
app returns the user to the exact state in which it was last used.
n- When the app is re-launched from Home or All Apps, the app restores the app
state as closely as possible to the previous state.
o- When pressing the Back key, the app gives the user the option of saving any app
or user state that would otherwise be lost on back-navigation.
a-The app does not crash, force close, freeze, or otherwise function abnormally on
any targeted device.
11-5
Flutter ™ Application Development
b- The app loads quickly or provides onscreen feedback to the user (a progress
indicator or similar cue) if the app takes longer than two seconds to load.
c- The app runs on the latest public version of the Android and iOS platform without
crashing or losing core function.
d- The app targets the latest SDK by setting the target SDK value in order to
minimize the use of any platform-provided compatibility fallbacks.
e- The app is built with the latest SDK by setting the compile SDK value.
f- Music and video playback is smooth which means there are no crackle, stutter, or
other artifacts, during normal app use and load.
g- The app displays graphics, text, images, and other UI elements without noticeable
distortion, blurring, or pixelation. The app provides high-quality graphics for all
targeted screen sizes and form factors.
h- The app displays text and text blocks in an acceptable manner. Make sure that
there is sufficient spacing between texts and surrounding elements.
4- Security
These criteria ensure that apps handle user data and personal information safely:
c- All intents and broadcasts follow best secure practices. Intents that contain data
and payload are verified before use.
h- The app does not dynamically load code from outside the app.
11-6
App Testing & Publishing AFD-200
The ideal testing environment would include a small number of actual hardware devices
that represent key form factors and hardware/software combinations currently available
to consumers. It’s not necessary to test the app on every device that’s on the market —
rather, you should focus on a small number of representative devices, even using one or
two devices per form factor.
If you are not able to obtain actual hardware devices for testing, you should set up
emulated devices (AVDs) to represent the most common form factors and hardware/
software combinations.
To go beyond basic testing, you can add more devices, more form factors, or new
hardware/software combinations to your testing environment. You can also increase the
number or complexity of tests and quality criteria.
Usability tests identify areas where users struggle with an app and thus help you
make recommendations for improvement. The goal is to better understand how real
users interact with your Flutter (Android and iOS) app and to improve the product
based on the results. The primary purpose of a usability test is to improve a design.
In a typical usability test, real users try to accomplish typical goals, or tasks, with a
product under controlled conditions. UX designers, UI designers, and development
team members watch, listen, collect data, and take notes. Since usability testing
employs real customers accomplishing real tasks, it can provide objective
performance data, such as time on task, error-rate, and task success. There is also
no substitute for watching users struggle with or have great success in completing
a task when using an app. This observation helps designers and developers gain
empathy with users and encourage them to think of alternative designs that better
support tasks and workflow.
You should check the usability test by participants before publishing your app on
Google Play store or Apple store because your purpose is to gain users’ satisfaction.
If these users start using your app and find something that does not work or is not
designed properly, your app will get negative reviews level on Google Play store or
Apple store. If this happens, you will then need to put a lot of effort to change this
feedback and sometimes negative reviews may lead to the end of a project because
other users would prefer to use other apps with positive reviews.
11-7
Flutter ™ Application Development
Your research participants must be able to represent your target group or end users;
otherwise, your results will not translate into something you can use.
To recruit participants that will represent real users for your app later, you have to
take into consideration many factors when making this choice.
In most projects, you need to consider the age group of your participants, their
geographical location, and if there is any specific type of experience they might have
that may be suitable.
When you start your test session, follow the following steps:
•• Welcome your participant and make them comfortable.
•• Use a script to help you remember what you need to do and say.
•• The participants should read the task scenarios and begin working on the
scenario step by step.
•• The participants should register the time needed to complete each task and the
total time to achieve the full scenario.
•• The participants should be asked to give their opinion about the way they used
to find items or navigation tools and if they were satisfied with the navigation
method used to move from one task to the next.
11-8
App Testing & Publishing AFD-200
You should ask participants after completing the task scenario the following questions:
•• How did you find yourself with this type of app? Were you familiar with it?
•• If this app was your app, what would you add or remove?
•• Did you find a guide or any other way to tell you how to use this app?
•• Are you satisfied to use this app for the purpose for which it is created?
•• Do you still remember the purpose of the app? This question is asked to make
sure that participants are serious in their testing tasks.
11-9
Flutter ™ Application Development
For more information about the Firebase test lab, check the following link: https://
firebase.google.com/docs/test-lab
The App Store is a digital distribution platform, developed and maintained by Apple Inc., for
mobile apps on its iOS operating system. The store allows users to browse and download
iOS apps.
Google Play, formerly Android market, is a digital distribution service operated and
developed by Google. It serves as the official app store for the Android operating system,
allowing users to browse and download applications developed with the Android software
development kit and
The following steps display how you should prepare your Flutter app to be ready to be
published in Google play store and Apple store:
11-10
App Testing & Publishing AFD-200
This topic is already explained step by step in lesson 5. However, in this lesson, you will
create app icons for your Android and iOS apps in an easier way as follows:
1- Create your app logo image, and be sure that it has a PNG extension and a transparent
background. To create your PNG image, you may use a software such as Adobe Photoshop
to remove the image background and save the image as a PNG image. You may also use
Google search engine to find a safe web site to create a free logo image. In this lesson, you
may use logo.png image which is in your:
3- In your project structure console, right click your project name → New → Directory as
illustrated in the following figure:
4- From your local hard disk, open : Lab Source Files → Images , then copy : logo.
png image. In your Android Studio, paste this logo image in the following folder:
images → icon,
11-11
Flutter ™ Application Development
5- In your Android Studio, open: pubspec.yaml file, then add the following code under dev_
dependencies:
flutter_launcher_icons: "^0.7.3"
Note : dev_dependencies are not related to app code; otherwise, they are related to the
Flutter development tools.
flutter_icons:
android: true
ios: true
image_path: "images/icon/logo.png"
11-12
App Testing & Publishing AFD-200
7- In your Android Studio, open the Terminal console (on the status bar), then type the
following command:
Then, press the Enter key (or Return for Mac) and type the following command:
Then, press the Enter key. You should get the following message:
Android minSdkVersion = 16
Creating default icons Android
Overwriting the default Android launcher icon with a new icon
Overwriting default iOS launcher icon with new icon
Then, check all the mipmap folders which include your Android app icon in different
sizes because your app may run on different screen sizes as illustrated in the
following figure:
11-13
Flutter ™ Application Development
To check your app icons for iOS, check the following path:
Stop your app and then run it again. Press your phone emulator home button, then
check your apps list. You should get the icon which you added in the previous step
as illustrated in the following figure:
11-14
App Testing & Publishing AFD-200
To add a splash image to your Android app, perform the following steps:
1- From your local hard disk, open : Lab Source Files → Images, then copy the
splash_logo.png image ( remember, the image name must include an underscore
character as part of image file name).
Then, paste this image inside all the mipmap folders (five folders) as illustrated in the
following figure:
Remove the comment “<!-- “ symbols and add the image which you added to the mipmap
folders without file extension as illustrated in the grey part of the following code.:
11-15
Flutter ™ Application Development
<!-- You can insert your own image assets here -->
<item>
<bitmap
android:gravity="center"
android:src="@mipmap/splash_logo" />
</item>
</layer-list>
4- Stop your app and run it again. You should get your splash image within the startup
process of your app as illustrated in the following figure:
To add a splash image to your iOS app, perform the following steps:
11-16
App Testing & Publishing AFD-200
2- Create three copies of the image which you want to make as the splash or
startup image for your iOS app, and name these images to have the same names
(LaunchImage.png , [email protected] , and [email protected]) .
4- Copy your three images. Then, paste them in the LaunchImage.imageset folder.
Open your lab source files folder on your computer, then open the following path:
Lab Source Files → Images → iOS Lunch Images, you will find these three images
ready to move to your LaunchImage.imageset folder in Android Studio as illustrated
in the following figure:
Now, you may test your app on your iPhone emulator. Stop your app and run it
again. You should get this image within the first launch of your app.
The next step in publishing Android and iOS app is for Android apps only.
Note: All the commands in the next steps are available in the web link below:
https://flutter.dev/docs/deployment/android
To avoid any typing errors or if you want to save time, you may copy and paste these
commands from this web site. However, at the same time follow the instructions
below of this book.
11-17
Flutter ™ Application Development
1- In your Android Studio IDE, in the Terminal console, type either of the following
lines of code, as applies to your operating system:
For Windows, you should replace USER_NAME with your computer admin user name.
To know what is your computer user name, just hold the Windows logo key and
then press R letter key, type cmd and press Enter. As you see in the snapshot below,
my computer user name is Admin.
Also, you should use the command prompt to run this keytool command. This
command should run on the same directory which includes this keytool.exe file. To
know where this tool exists, go to:
C:\ → Program Files → Java → jre1.xxx → bin (xxx depending on your version number).
Make sure that this bin folder includes the keytool.exe file, then perform the
11-18
App Testing & Publishing AFD-200
following steps:
2- Use cd command (Change Directory) to move to the directory of the tool. Then,
add the path of this bin folder as you see in the following figure:
3- Type the keytool command using your user name as illustrated in the following
figure:
4- You will be asked to enter and confirm the password for keystore as illustrated in
the following figure:
5- Now, answer the following questions such as your first and last name,
organization name, organization unit (the folder name which will include your
profile data), city, state, and the country (first two letters only), type Yes if all the
information is correct, and press Enter . Then, you will be asked to enter the store
password as illustrated in the following figure:
11-19
Flutter ™ Application Development
Now, your signature file (key.jks) has been created and saved on your hard disk as
illustrated in the following figure:
The next step is: Reference the keystore from the app. To do this, perform the
following steps:
1- In your Android Studio, right click the android folder, then select → New → File
Type: key.properties for the file name, then click OK as illustrated in the following figure:
11-20
App Testing & Publishing AFD-200
2- In Android Studio, open this file: key.properties , then type the following configurations:
Remember to keep the key.properties file private; do not check it into public source control.
In some cases, you share your app files with others using Github web site, it is
important to exclude this file. To do that, open the following file in Android Studio:
Then, add this file name to the list as illustrated in the following figure:
11-21
Flutter ™ Application Development
3- Open android → app → build.gradle file and make the following two changes in this file:
a- To Load the key.properties file into the keystoreProperties object, add only the
following grey highlighted code before the android block code :
android {
compileSdkVersion 28
.....
.....}
buildTypes {
release {
// TODO: Add your own signing config for the release build. //
Signing with the debug keys for now, so 'flutter run --release' works.
signingConfig signingConfigs.debug
}
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ?
11-22
App Testing & Publishing AFD-200
file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
<app dir> → android → app → src → main → AndroidManifest.xml and if your app needs
internet connection, add only the following grey highlighted code to your AndroidManifest.
xml to give your app the permission to access the internet:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.androidatc.googlemap">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
...
...
2- Type the following command: flutter build appbundle and press Enter.
11-23
Flutter ™ Application Development
The previous figure displays that my bundle file has been created and it is found in the following
path on my computer: D:\Lesson10\google_map\build\app\outputs\bundle\release
Before you go to the Google Play store, there is an important part of your Flutter app
that needs explanation. Open your pubspec.yaml file. At the beginning of this file,
you will find the following configuration:
version: 1.0.0+1
This number represents your Flutter app version. When you want to publish a new
version of your app including your app updates, you must increment this number,
then upload the new version to our Google Play store. Then, your app users will
receive a notification displaying a new update for your app.
11-24
App Testing & Publishing AFD-200
1- Go to: https://play.google.com/apps/publish/signup
Login using your Gmail account, then you will get the following figure:
2- Scroll down this web page, in the Accept developer agreement section, select I
agree, then click : CONTINUE TO PAYMENT button.
3- You will get the payment page. The Developer Registration Fee is 25 USD for a life time.
If you want to continue the publishing your app, you will be required to enter your credit
card information. The following screenshots will give you enough knowledge about how to
publish an Android app on Google Play store without the need to pay at this time being.
11-25
Flutter ™ Application Development
4-After completing the payment step, you will be asked to complete your account
details. Here, you will fill out a form that verifies you about your name, email
address, web site, and phone number. After filling out this data, click the COMPLETE
REGISTRATION button as illustrated in the following figure:
5- To add your app to Google Play store, click : CREAT APPLICATION button as
illustrated in the following figure:
6- Then, type your app name. For example, this app is to test publishing Android app
only, type:
11-26
App Testing & Publishing AFD-200
7- You will get a form asking you to fill out some information about your app as follows :
The above details are important because they help app users to have an idea about
the purpose of creating this app, and how to use it.
8- Scroll down until reaching the following part which is related to uploading screenshots
to your app as illustrated in the following figure. Add some screenshots to your app. These
images must be carefully selected because this will create the first impression for your app,
and if these are clear and organized to give the app user a good idea about your app, the user
will most likely download your app, otherwise he/she may select another competitor app.
11-27
Flutter ™ Application Development
Complete all the required information in this page such as email, web site, telephone
number, and so on.
9- On the left side of your Google Play Console, click Pricing & distribution. Click
Free to make your app free for download . If it is Paid, you should configure the price
template and other configurations.
Also, under Countries section, click Available to make your app available to
download across all countries as illustrated in the following figure:
Scroll down and answer the following question: Does your application have ads?
Select No, it has no ads.
10- On the left side of your Google Play Console, click App releases, then on the
right side under Production, click MANAGE , then you will get the following figure:
11-28
App Testing & Publishing AFD-200
Click CREATE RELEASE button and click Continue to get the following figure. Click
BROWSE FILES button to upload your app bundle which you have created in the
previous steps. My file is in the following path : D:\Lesson10\google_map\build\
app\outputs\bundle\release. Select your file, and wait till it completes uploading.
After uploading your app bundle, you will get the following figure which displays that
your app has been uploaded successfully.
11-29
Flutter ™ Application Development
11- After you complete filling all the required information about your app, you should get green
marks on the right side of your Google Play Console as illustrated in the following figure:
If you click the Dashboard, you will find the following message from Google Play
store as illustrated in the following figure:
11-30
App Testing & Publishing AFD-200
It will take up to 7 days or longer in exceptional cases for your app to be thoroughly
reviewed before it is finally published. In my case, I waited for 10 minutes, then I
clicked App release in the Google Play Console, then as illustrated in the following
figure, I clicked START ROLLOUT TO PRODUCTION
Finally, this app became available for all users on Google Play store.
11-31
Flutter ™ Application Development
The following figure displays the release dashboard after publishing your Android app.
To publish your iOS app on Apple store, you must enroll in the Apple Developer Program.
The cost of membership is 99 USD per year. To enroll in this program, check the
following web site: https://developer.apple.com/programs/enroll
Now, assume that your Apple account is your Apple developer account and you
want to register your iOS app on App Store Connect. App Store Connect is where
you will manage your app’s life cycle. You will define your app name and description,
add screenshots, set pricing, and manage releases to the App Store .
Registering your app involves two steps: registering a unique Bundle ID and creating
an application record on App Store Connect.
Note: all the web links for creating Apple ID and registering a bundle id are available
in the following web link: https://flutter.dev/docs/deployment/ios
11-32
App Testing & Publishing AFD-200
Note: You should use a Mac device to complete the following steps:
5. Select the services your app will use, then click Continue.
6. n the next page, confirm the details and click Register to register your
O
Bundle ID.
After completing registering your iOS app and getting its bundle ID, the next step is
registering your app on App Store Connect.
3. Click + in the top-left corner of the My Apps page, then select New App.
4. ill in your app details in the form that appears. In the Platforms section,
F
ensure that iOS is checked. Since Flutter does not currently support tvOS,
leave that checkbox unchecked. Click Create.
5. avigate to the application details for your app and select App
N
Information from the sidebar.
11-33
Flutter ™ Application Development
In this step, you’ll review the most important settings in the Xcode workspace.
2. o view your app’s settings, select the Runner project in the Xcode project
T
navigator. Then, in the main view sidebar, select the Runner target.
Display Name:
The name of the app to be displayed on the home screen and elsewhere.
Bundle Identifier:
The App ID you registered on App Store Connect.
Team:
Select the team associated with your registered Apple Developer account. If
required, select Add Account…, then update this setting.
Deployment Target:
The minimum iOS version that your app will support. Flutter supports iOS 8.0 and
later. If your app includes Objective-C or Swift code, it makes use of APIs which was
unavailable in iOS 8. So, update these settings appropriately.
The General tab of your project settings should resemble the following:
11-34
App Testing & Publishing AFD-200
During development, you’ve been building, debugging, and testing with debug builds.
When you’re ready to ship your app to users on the App Store or TestFlight, you’ll
need to prepare a release build.
1. Run flutter build ios to create a release build (flutter build defaults
to --release).
2. To ensure that Xcode refreshes the release mode configuration, close and re-
open your Xcode workspace. For Xcode 8.3 and later, this step is not required.
11-35
Flutter ™ Application Development
4. S elect Runner in the Xcode project navigator, then select the Runner target in
the settings view sidebar.
5. I n the Identity section, update the Version to the user-facing version number
you wish to publish.
6. I n the Identity section, update the Build identifier to a unique build number
used to track this build on App Store Connect. Each upload requires a unique
build number.
2. In the sidebar of the Xcode Organizer window, select your iOS app, then select
the build archive you just produced.
3. C
lick the Validate App button. If any issues are reported, address them and
produce another build. You can reuse the same build ID until you upload an
archive.
4. A
fter the archive has been successfully validated, click Distribute App. You
can follow the status of your build in the Activities tab of your app’s details
page on App Store Connect.
You should receive an email within 30 minutes notifying you that your build has been
validated and is available to be released to testers on TestFlight. At this point you can
choose whether to release TestFlight, or go ahead and release your app to the App Store.
TestFlight allows developers to push their apps to internal and external testers. In
this optional step, you’ll release your build on TestFlight.
Navigate to the TestFlight tab of your app’s application details page on App Store
Connect.
3. Add the email addresses of any internal testers. You can add additional
internal users in the Users and Roles page of App Store Connect available
11-36
App Testing & Publishing AFD-200
from the dropdown menu at the top of the page. You can invite up to 10,000
testers using their email address or by sharing a public link.
1. Select Pricing and Availability from the sidebar of your app’s application
details page on App Store Connect, and complete the required information.
2. Select the status from the sidebar. If this is the first release of this app, its
status will be 1.0 Prepare for Submission. Complete all required fields.
Apple will notify you when their app review process is complete. Your app will be
released according to the instructions you specified in the Version Release section.
11-37
Flutter ™ Application Development
You can now count yourself among Flutter application developers who can create
Android and iOS apps from A to Z.
At this point, you are confident to apply for the Flutter application development
exam (Exam code: AFD-200) and become a Flutter Certified application developer by
Android ATC.
To know more information about how to apply for this exam, check Android ATC
web site www.androidatc.com (Certifications & Exams tab). You will also have
access to more information about the exam procedures, exam samples and other
Android ATC services.
Last but not least, we would love to know your feedback after completing this
course and how we can make it even better for you.
11-38