Flutter tutorial for Beginner Step by Step

3,125 views 189 slides Oct 08, 2020
Slide 1
Slide 1 of 189
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36
Slide 37
37
Slide 38
38
Slide 39
39
Slide 40
40
Slide 41
41
Slide 42
42
Slide 43
43
Slide 44
44
Slide 45
45
Slide 46
46
Slide 47
47
Slide 48
48
Slide 49
49
Slide 50
50
Slide 51
51
Slide 52
52
Slide 53
53
Slide 54
54
Slide 55
55
Slide 56
56
Slide 57
57
Slide 58
58
Slide 59
59
Slide 60
60
Slide 61
61
Slide 62
62
Slide 63
63
Slide 64
64
Slide 65
65
Slide 66
66
Slide 67
67
Slide 68
68
Slide 69
69
Slide 70
70
Slide 71
71
Slide 72
72
Slide 73
73
Slide 74
74
Slide 75
75
Slide 76
76
Slide 77
77
Slide 78
78
Slide 79
79
Slide 80
80
Slide 81
81
Slide 82
82
Slide 83
83
Slide 84
84
Slide 85
85
Slide 86
86
Slide 87
87
Slide 88
88
Slide 89
89
Slide 90
90
Slide 91
91
Slide 92
92
Slide 93
93
Slide 94
94
Slide 95
95
Slide 96
96
Slide 97
97
Slide 98
98
Slide 99
99
Slide 100
100
Slide 101
101
Slide 102
102
Slide 103
103
Slide 104
104
Slide 105
105
Slide 106
106
Slide 107
107
Slide 108
108
Slide 109
109
Slide 110
110
Slide 111
111
Slide 112
112
Slide 113
113
Slide 114
114
Slide 115
115
Slide 116
116
Slide 117
117
Slide 118
118
Slide 119
119
Slide 120
120
Slide 121
121
Slide 122
122
Slide 123
123
Slide 124
124
Slide 125
125
Slide 126
126
Slide 127
127
Slide 128
128
Slide 129
129
Slide 130
130
Slide 131
131
Slide 132
132
Slide 133
133
Slide 134
134
Slide 135
135
Slide 136
136
Slide 137
137
Slide 138
138
Slide 139
139
Slide 140
140
Slide 141
141
Slide 142
142
Slide 143
143
Slide 144
144
Slide 145
145
Slide 146
146
Slide 147
147
Slide 148
148
Slide 149
149
Slide 150
150
Slide 151
151
Slide 152
152
Slide 153
153
Slide 154
154
Slide 155
155
Slide 156
156
Slide 157
157
Slide 158
158
Slide 159
159
Slide 160
160
Slide 161
161
Slide 162
162
Slide 163
163
Slide 164
164
Slide 165
165
Slide 166
166
Slide 167
167
Slide 168
168
Slide 169
169
Slide 170
170
Slide 171
171
Slide 172
172
Slide 173
173
Slide 174
174
Slide 175
175
Slide 176
176
Slide 177
177
Slide 178
178
Slide 179
179
Slide 180
180
Slide 181
181
Slide 182
182
Slide 183
183
Slide 184
184
Slide 185
185
Slide 186
186
Slide 187
187
Slide 188
188
Slide 189
189

About This Presentation

Learn Flutter with 42 examples.
http://rrtutors.com/


Slide Content

Table of Content

Introduction 5
Flutter Installation 6
Application Folder Structure 10
Dart Basics 11
Variables 11
Defining a map 14
Functions 15
Named parameter 16
Default value parameter 16
Control flow 17
Loops 17
For Loop 17
While loop 18
Do-while loop 18
Switch 18
Exception handling 19
Flutter - Widgets 21
What is a widget? 21
Platform specific widgets 22
Material Widgets 22
Cupertino Widgets 23
Layout Widgets 23
Single Child Widgets 24
Multi Child Widgets 24
Example of widgets and Layout widgets 25
Image 26
Load Network Image 26
Load Image from Assets 27
Icon 29
Buttons 30
Button Examples 31
Multi Child Layouts 35
Flutter - Linear Layout 35
Framelayout in Flutter 38
2

Flex Widget 39
Like Row Widget 41
Like Column Widget 42
Weight Property like Android in Flex widget 43
Listview 44
How will we handle the item click events? 45
Dynamic ListView 46
Listview.separated 48
Examples of Single Child Layout Widgets 50
Container 50
Card 52
Expanded 54
Flexible 57
Center 58
GestureDetector 58
Positioned 61
SafeArea 64
SingleChildScrollView 64
Themes 67
Scaffold 68
Dialogs 73
Simple AlertDialog 73
Add buttons to Alert Dialogs 74
How to close Dialog 74
ExpansionPanelList & ExpansionPanel 78
ExpansionPanel 78
ExpansionPanelList 78
GridView 83
PopupMenu 86
Checked Widgets 88
CheckBox 88
CheckboxListTile 89
Radio 89
TabBar TabBarView 95
Table 97
Future and FutureBuilder 101
FutureBuilder 102
3

StreamBuilder 105
Navigation 108
Routing table (Named Routes) 113
Navigation switch animation 117
Form & Form Fields 118
Form State 118
Form Validation 119
Input Decoration Themes 123
Networking & JSON and Serialization 126
HTTP Introduction 126
HTTPClient 126
Make HTTPRequest 126
Decode and encode JSON 127
HTTP Library 131
CompleteExample 135
Database and local storage 141
SharedPreferences 141
How to access Shared Preferences in Flutter? 141
Database 145
How to access SQLite in Flutter? 145
SQFlite Features 145
Database operations 147
Create Table 147
Query 149
State Management 161
Stateful Widget 161
InheritedWidget 162
BLoC 165
What is BLoC? 165
Example 166
Firebase Integration 169
Firebase Setup 169
Firebase authentication & Google sign in using Flutter 174
Chat Application with Firebase database Flutter 181


4

Introduction

Flutter is an open-source UI software development kit created by Google. It
is used to develop applications for Android, iOS, Windows, Mac, Linux,
Google Fuchsia and the web.

Flutter is Google's mobile UI framework that can quickly build high-quality
native user interfaces on iOS and Android. Flutter works with existing code.
Flutter is being used by more and more developers and organizations
around the world, and Flutter is completely free and open source . At
present, some modules of the company are developed using Flutter
.
The major components of Flutter include:

Dart platform
Flutter engine
Foundation library
Design-specific widgets

Dart Platform
Flutter apps are written in the Dart language and make use of many of the
language's more advanced features

You can refer Dart Language at Dart



5

Flutter Installation

Flutter is supporting HybridApp development on different Os.
To set up the flutter on each individual os by this Flutter official Tutorial


In this section we will learn how to install Flutter SDK in Windows system.

Step 1: Download Flutter SDK from Official website The Latest version is
1.12
Step 2: Unzip and archive file in specific folder, like c:\flutter\
Step 3: Update the system path to include flutter bin directory
Step 4: Open terminal and move to installed directory and run


flutter doctor


flutter doctor is tool to check all requirements for the flutter is installed
or not and show the details

The result of the above command will give you

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel master, v1.14.6-pre.51, on Microsoft Windows
[Version 6.3.9600], locale en-IN)
[√] Android toolchain - develop for Android devices (Android SDK
version 28.0.3)
[√] Chrome - develop for the web
[√] Android Studio (version 3.3)
[!] Android Studio (version 3.4)
6

X Flutter plugin not installed; this adds Flutter specific
functionality.
X Dart plugin not installed; this adds Dart specific functionality.
[√] Connected device (2 available)

! Doctor found issues in 1 category.

Step 5: Install Android Studio
Step 6: Check Latest Android SDK installed or not, if not install it
Step 7: Open Android studio and install Dart and Flutter Plugins for
Android studio.
● Click File > Settings > Plugins.
● Select the Flutter plugin and click Install.
● Click Yes when prompted to install the Dart plugin.
● Restart Android studio
Flutter – Creating Simple Application in Android Studio

Now Open File -> Create new Flutter Project



It will prompt below screen
7

Select Flutter application and press Next

Now it will ask below details


8

●Enter your Project Name
●Set Flutter SDk path (It is installation path)
●Set the Project Location
●Press Next Button

Enter Domain name and Press Finish

Now it will create a project with auto generated code

Now connect real device/Emulator and run the application

The output will be like this


9

Application Folder Structure
To understand flutter fully we need to understand the first Flutter folder
structure.
●android - Auto generated source code to create android application
● ios - Auto generated source code to create ios application
● web - Auto generated source code to create web application
●lib - Main folder containing Dart code written using flutter
framework
● lib/main.dart - Entry point of the Flutter application
● test - Folder containing Dart code to test the flutter application
● test/widget_test.dart - Sample code
● .gitignore - Git version control file
● .metadata - auto generated by the flutter tools
● .packages - auto generated to track the flutter packages
● .iml - project file used by Android studio
● pubspec.yaml - Used by Pub, Flutter package manager
● pubspec.lock - Auto generated by the Flutter package manager,
Pub
● README.md - Project description file written in Markdown format










10

Dart Basics
Dart is an open-source general-purpose programming language. It was
originally developed by Google.
Dart is an object-oriented language with C-style syntax. It supports
programming concepts like interfaces, classes, unlike other programming
languages Dart doesn’t support arrays.
Dart collections can be used to replicate data structures such as
arrays, generics, and optional typing.
The following code shows a simple Dart program


void main () {
print ( 'Hello, World!' );
}


Every Dart application contains main() functions, from here code will
execute.

Variables
Variable is named storage location and Data types simply refers to the type
and size of data associated with variables and functions.
Dart uses a var keyword to declare the variable.
The syntax of var is defined below

var name = 'Flutter' ;

Dart provide us various built in data types
Numbers
11

As Other Programming languages to Java or C++ Dart does not have
anything like float or long. Dart offers just two types of number
Int
Double
Strings : It represents a sequence of characters. String values are specified
in either
single or double quotes

Booleans : Dart uses the bool keyword to represent Boolean values – true
and false
Lists & Maps : It is used to represent a collection of objects
Runes : Represents string Unicode coded characters (UTF-32 code
points), etc
Symbols : Use a Symbol literal to obtain the symbol's symbol object, which
is to add a # symbol in front of the identifier

String name = 'Flutter' ;

Here String is Data type, name is variable name and Flutter is value of
variable

var name = 'Flutter' ;

The type of the name variable is inferred as String.
The compiler will check we have var keyword not String so type depends on
value which in this case is String

Example:

void main() {
String fName = 'Chandu';
var lName='Mouli';
int intValue = 123;
print(fName);
print(lName);
12

print(intValue);
}
Output will be
Chandu
Mouli
123

List : Declare a list is very simple, you can simply use square brackets [] to
define the list. The following are common operations for lists

main(List<String> args) {
var list = [1,2,3,4];

print(list); //Output: [1, 2, 3, 4]
//Length
print(list.length);

//Selecting single value
print(list[1]); //Output: 2

//Adding a value
list.add(10);

//Removing a single instance of value
list.remove(3);

//Remove at a particular position
list.removeAt(0);
}


If we want to define a compile-time constant list, for example, the contents
of the list are immutable, you can use keywords const

13

main(List<String> args) {
var list = const [1,2,3,4];
}

Defining a map
We can define maps by using curly braces {}


main(List<String> args) {
var map = {
'key1': 'value1',
'key2': 'value2',
'key3': 'value3'
};

//Fetching the values
print(map['key1']); //Output: value1
print(map['test']); //Output: null

//Add a new value
map['key4'] = 'value4';

//Length
print(map.length);

//Check if a key is present
map.containsKey('value1');

//Get entries and values
var entries = map.entries;
var values = map.values;
}

We can also define Map by constructor

14

main(List<String> args) {
var squares = new Map();
squares[4] = 16;
}

Functions

Functions in dart are similar to those in JavaScript.
It consists of the function name, return value, and parameters.

main(List<String> args) {
var name = fullName('Chandu', 'Mouli');
print(name);
}

String fullName(String firstName, String lastName) {
return "$firstName $lastName";
}

return type is an option, if we can remove return type and function looks
like below

main(List<String> args) {
var name = fullName('Chandu', 'Mouli');
print(name);
}
fullName(String firstName, String lastName) {
return "$firstName $lastName";
}

15

If the function having single line we can write it as

main(List<String> args) {
var name = fullName('Chandu', 'Mouli');
print(name);
}

fullName(String firstName, String lastName) => "$firstName
$lastName";


Named parameter
Dart provides Named parameters while calling the functions

main(List<String> args) {
var name = fullName(firstName: 'Chandu', lastName: 'Mouli');
print(name);
}

fullName({String firstName, String lastName}) {
return "$firstName $lastName";
}

Default value parameter
If we didn't pass parameter to function call we can define a default value to
the parameters

main(List<String> args) {
16

var name = fullName(firstName: 'Chandu');
print(name);
}
fullName({String firstName, String lastName = "Shekar"}) {
return "$firstName $lastName";
}


Control flow
If - else This is similar to other programing languages If - else

main(List<String> args) {
var day = 6;

if (number > 7) {
print('Not a Week Day');
} else if (number < 100) {
print('Week Day');
}
}


Loops
For Loop
main(List<String> args) {
for (int i = 0; i < 10; i++) {
print('$i');
}
}

17

While loop

main(List<String> args) {
int i = 0;
while(i < 10) {
print('$i');
i++;
}
}

Do-while loop
main(List<String> args) {
int i = 0;
do {
print('$i');
i++;
} while (i < 10);
}


Switch
main(List<String> args) {
int day = 5;
switch(age) {
case 1:
print('Sunday.');
break;
case 2:
print('Monday.');
break;
18

case 3:
print('Tuesday');
break;
case 4:
print('Wednesday');
break;
case 5:
print('Thursday');
break;
case 6:
print('Friday');
break;
case 7:
print('Saturday');
break;
}
}


Exception handling
Similar to other programing languages dart also we can handle exceptions
by
Try, catch blocks and throw exceptions by throw keyword

main(List<String> args) {
divide(10, 0);
}
divide(int a, int b) {
if (b == 0) {
throw new IntegerDivisionByZeroException();
}
return a / b;
}

19

Let’s catch the exception pass catch block

main(List<String> args) {
try {
divide(10, 0);
} on IntegerDivisionByZeroException {
print('Division by zero.');
}
}
divide(int a, int b) {
if (b == 0) {
throw new IntegerDivisionByZeroException();
}
return a / b;
}













20

Flutter - Widgets

Now you are not having knowledge on flutter basics then go with Technical
overview

What is a widget?
Everything within a flutter application is widget. From basic
"text","Buttons" to "Screen Layouts".
In flutter application everything is designed by widget only.
These widgets are arranged in hierarchical order to be displayed onto the
screen.
In the Flutter widgets most of widgets are Container widgets unlike Text
widget

Widgets are two types
●Stateless Widget
●Stateful widget

All Widgets are categorized into below groups
1.Platform specific widgets
2.Layout widgets
3.State maintenance widgets
4.Platform independent / basic widgets

21

Platform specific widgets
Flutter provides platform specific widgets like Android and Ios

Android specific widgets are designed based on Material design rules
These widgets are called Material Widgets

Ios specific widgets are designed based on Human Interface Guidelines by
Apple,
These widgets are called Cupertino widgets

Material Widgets
Scaffold
AppBar
BottomNavigationBar
TabBar
TabBarView
ListTile
RaisedButton
FloatingActionButton
FlatButton
IconButton
DropdownButton
PopupMenuButton
ButtonBar
TextField
Checkbox
Radio
Switch
Slider
Date & Time Pickers
22

SimpleDialog
AlertDialog

Cupertino Widgets

CupertinoButton
CupertinoPicker
CupertinoDatePicker
CupertinoTimerPicker
CupertinoNavigationBar
CupertinoTabBar
CupertinoTabScaffold
CupertinoTabView
CupertinoTextField
CupertinoDialog
CupertinoDialogAction
CupertinoFullscreenDialogTransition
CupertinoPageScaffold
CupertinoPageTransition
CupertinoActionSheet
CupertinoActivityIndicator
CupertinoAlertDialog
CupertinoPopupSurface

Layout Widgets
Layout widgets are widgets which will arrange the widget on the screen.
Examples: Container,Column,Row,Stack....

23

Single Child Widgets
Container
Padding
ConstrainedBox
Baseline
FractinallySizedBox
IntrinsicHeight
IntrinsicWidth
LimitedBox
OffStage
OverflowBox
SizedBox
SizedOverflowBox
Transform
CustomSingleChildLayout
Align

Multi Child Widgets
Row
Column
ListView
GridView
Expanded
Table
Flow
Stack

24

Example of widgets and Layout widgets

First create a simple visible widget

Text("Text widget")


If we want to add this visible widget to the Screen we need to put this
widget inside the layout widget.
Let's create layout widget


Container(
child: Text("Text Widget")
)


Now let;s add this Lyoutwidget to the screen by


class Sample1 extends StatelessWidget{
@override
Widget build (BuildContext context)
{
return Container(
child: Text("Text Widget");
)
}
}

25

Image
Image widget used to show an image. When displaying
an image, you specify the image source in the constructor:
image provider
asset,
network,
file,
memory

Load Network Image

class ImageWidget extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: SafeArea(
child: Scaffold(
body: Center(child:
Image.network( "https://cdn.pixabay.com/photo/2016/07/0
3/16/06/global-warming-1494965_960_720.jpg" ,width:
200 ,))
),
),
);
}

}

26

Load Image from Assets
To load images from assets first we need to create an Assets folder inside
the application.
It could be like below



Now after adding image into assets folder we need to set the path inside
pubspec.yaml file

27

Next run the below command in terminal to configure image

flutter packages get

Now lets create sample

class ImageWidget extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: SafeArea(
child: Scaffold(
body: Center(child: Image.asset( "assets/user.png" ,width:
200 ,))
),
),
);
}
}

While Loading the images there is no option to show placeholder with
above way,
Then how to show Placeholder while loading the image.
With FadeInImage widget we can achieve to show placeholder image
Replace above code with
Scaffold(
body: Center(child: FadeInImage.assetNetwork(placeholder:
"assets/user.png" ,
image:
"https://cdn.pixabay.com/photo/2016/07/03/16/06/globa
l-warming-1494965_960_720.jpg" ,width: 200 ,))
)
28

Icon

The icon widget allows us to quickly build icon widgets
using a pre-built list of material icons, available in the
Icons class.
We can specify the icon size and color


class IconWidget extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: SafeArea(
child: Scaffold(
29

body: Center(child: Icon(Icons. email ,color: Colors. pink ,size:
48 ,))
))
,
);
}

}


Buttons
We can’t imagine a programming language without click events. Similarly
other languages flutter provided buttons to handle click events.
We have different types of buttons in flutter
FlatButton
RaisedButton
IconButton
OutlineButton
DropdownButton
BackButton
CloseButton
FloatingActionButton

All these buttons click event is handled by onPressed()

onPressed: (){
}

FlatButton : This type of button doesn't have any border, When we click on
it it will show press effect
RaisedButton : When we need to show some decoration we can use this
button
30

IconButton : It is a material button, Flashes background circle when clicked
on
OutlineButton : A bordered button whose elevation increases and
whose background becomes opaque when the
button is pressed
DropDownButton : It is a Material widget, Which is used for selecting from
a list of items
It similar to Spinner in Android
CloseButton : An IconButton setup for use as a close button to
close modals (or any other closeable content).
Flashes background circle when clicked on
FloatingActionButton: It is a Material widget button, A button that hovers
in a layer above content

Button Examples

class ButtonWidget extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return ButtonsWidgetState();
}

}

class ButtonsWidgetState extends State<ButtonWidget>{
var selected_item = "Please choose a location" ;
List<String> list =[
"Please choose a location" ,
"Item One" ,
"Item Two" ,
"Item Three" ,
"Item Four" ,
];
31

@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: SafeArea(child: Scaffold(
appBar: AppBar(title: Text( "Buttons" ),backgroundColor:
Colors. pink ,),
body: Container(
child: Center(
child: Column(
children: <Widget>[
FlatButton(onPressed: (){
debugPrint( 'Button Clicked ' );
}, child: Text( "Flat Button" )),

RaisedButton(onPressed: (){
debugPrint( 'Button Clicked ' );
},child: Text( "Raised Button" ),),

OutlineButton(onPressed: (){
debugPrint( 'Button Clicked ' );
},child: Text( "Outline Button" ),highlightedBorderColor:
Colors. pink ,),

IconButton(onPressed: (){
debugPrint( 'Button Clicked ' );
},icon: Icon(Icons. add ),color: Colors. pink ,),

DropdownButton(


items: list .map((value){
return DropdownMenuItem(child: Text(value),value:
value);
}).toList(),
hint: Text( "Please choose a location" ),
value: selected_item ,
onChanged: (value){
32

selected_item =value;
setState(() {
});
debugPrint( 'Changed: ${value} ' );
},
)
BackButton(onPressed: (){
debugPrint( 'Button Clicked ' );
},color: Colors. pink ,),
CloseButton(),
FloatingActionButton(onPressed: (){
debugPrint( 'Button Clicked ' );
}, child: Icon(Icons. search ),backgroundColor: Colors. pink ,)
],
),
),
),
)),
);
}
}
33

34

Multi Child Layouts

Flutter - Linear Layout
In Android we have a linear layout to arrange childs in horizontal and
vertical, similarly in flutter we can arrange by Row, Column widgets.

Example
Horizontal Arrangement by Row

class RowWidget extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Tutorial' ,
theme: ThemeData(
primarySwatch: Colors. blue ,
),
home: Scaffold(
body: SafeArea(child:
Container(
color: Colors. brown ,
child: Row(
mainAxisSize: MainAxisSize. min ,
crossAxisAlignment: CrossAxisAlignment. start ,
children: <Widget>[
Text( "Header" ,style: TextStyle(color: Colors. white ),),
Icon(Icons. account_circle ,size: 100 ,color: Colors. white ,),
Text( "Name " ,style: TextStyle(color: Colors. white ))
],
),
)),
),
35

);
}
}
Vertical Arrangement by Column

class ColumnWidget extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Tutorial' ,
theme: ThemeData(
primarySwatch: Colors. blue ,
),
home: Scaffold(
body: SafeArea(child:
Container(
color: Colors. brown ,
child: Column(
mainAxisSize: MainAxisSize. max ,
children: <Widget>[
Text( "Header" ,style: TextStyle(color: Colors. white ),),
Icon(Icons. account_circle ,size: 100 ,color: Colors. white ,),
Text( "Name " ,style: TextStyle(color: Colors. white ))
],
),
)),
),
);
}
}





36

We can see the arrangement of children horizontal/vertical in below screen
Row
wrap_content
Row
match_parent
Column
wrap_content
Column
match_parent

How to set the Gravity for these widgets

We can set the Gravity by using CrossAxisAlignment

How it will work for Row and Column widgets
If we set the property for the Row it will align based on Vertical
direction(center,start,end…)
If we set the property for Column it will align based on Horizontal
direction(center,start,end…)



37

Framelayout in Flutter
Flutter uses Stack widgets to control child widgets at a layer. Child widgets
can completely or partially cover the base widgets.

Stack control positions its children relative to the edges of its box. This class
is useful if you just want to overlap multiple child widgets.


class StackWidget extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Tutorial' ,
theme: ThemeData(
primarySwatch: Colors. blue ,
),
home: Scaffold(
body: SafeArea(child:
Center(
child: Stack(
alignment: const Alignment( 0 , 0 ),
children: <Widget>[

Image.network( "https://cdn.pixabay.com/photo/2017/04/23
/19/17/climate-change-2254711_960_720.jpg" ),

Container(
decoration: BoxDecoration(
color: Colors. white ,
),
child: Text( 'GLobal Warming' ,style: TextStyle(fontSize:
20 ),),
),
],
38

),
)),
),
);
}
}



Flex Widget
The Flex Widget is similar to Row and Column widget.
We can use it as Row and Column by specifying the direction property.

class FlexWidget extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Tutorial' ,
theme: ThemeData(
primarySwatch: Colors. blue ,
),
home: Scaffold(

body: SafeArea(child:
Container(
color: Colors. brown ,
child: Flex(
direction: Axis. vertical ,
mainAxisSize: MainAxisSize. min ,
mainAxisAlignment: MainAxisAlignment. center ,
children: <Widget>[
Container(child: Padding(
padding: const EdgeInsets.all( 8.0 ),
child: Text( "Header" ,style: TextStyle(color: Colors. white ),),
39

),color: Colors. green ,),
Container(child: Icon(Icons. account_circle ,size: 100 ,color:
Colors. white ,),color: Colors. yellow ,),
Container(child: Padding(
padding: const EdgeInsets.all( 8.0 ),
child: Text( "Name " ,style: TextStyle(color: Colors. white )),
),color: Colors. pink ,)
],
),
),
),
),
);
}
}


Change different alignment and check the result














40

Like Row Widget
Direction Horizontal
wrap_content
Direction Horizontal
match_parent










41

Like Column Widget
Direction Vertical
wrap_content
Direction Vertical
match_parent



42

Weight Property like Android in Flex widget

If we add more items inside flex , to fit all these we can use Expandable
widget to set each child flex .

Flex(
direction: Axis. horizontal ,
mainAxisSize: MainAxisSize. min ,
mainAxisAlignment: MainAxisAlignment. center ,

children: <Widget>[
Flexible(
flex: 1 ,
child: Container(child: Padding(
padding: const EdgeInsets.all( 8.0 ),
child: Text( "Header" ,style: TextStyle(color: Colors. white ),),
),color: Colors. green ,),
),

Flexible(flex: 1 ,child: Container(child:
Icon(Icons. account_circle ,size: 100 ,color: Colors. white ,),color:
Colors. yellow ,)),
Flexible(flex: 1 ,
child: Container(child: Padding(
padding: const EdgeInsets.all( 8.0 ),
child: Text( "Name " ,style: TextStyle(color: Colors. white )),
),color: Colors. pink ,),
),
],
)


43

Listview
If we have more items to make them scrollable if the screen of the user
device is smaller than the content of the control. In Flutter, the easiest way
is to use ListView

Here simple listview example

class ListViewWidget extends StatefulWidget {
ListViewWidget({Key key}) : super(key: key);

@override
ListViewWidgetState createState() => ListViewWidgetState();
}

class ListViewWidgetState extends State<ListViewWidget> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.pink,
title: Text("Listview"),
),
body: _getListData(),
),
);
}

_getListData() {


List<Widget> widgets = [];
for (int i = 0; i < 100; i++) {
widgets.add( Card(
margin: EdgeInsets.all(5),
44

child: ListTile(
title: Text("Row $i"),
leading: Icon(Icons.account_circle),
trailing: Icon(Icons.arrow_forward_ios,size: 14,),
),
));
}
return ListView(children: widgets);
}
}

How will we handle the item click events?
ListTile has the property of onTap() function, with this we can handle the
Click events of each child item.


onTap: (){
_scaffoldKey.currentState.showSnackBar(SnackBar(content:
Text("Clicked on Child $i")));
},
45

Dynamic ListView
The above example shows all static static widgets data. If we want to show
dynamic data then we need to use
ListView.Builder()

class ListViewWidget extends StatefulWidget {
ListViewWidget({Key key}) : super(key: key);
46

@override
ListViewWidgetState createState() => ListViewWidgetState();
}

class ListViewWidgetState extends State<ListViewWidget> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.pink,
title: Text("Listview"),
),
body: _getDynamicList(),
),
);
}
_getDynamicList()
{
var countries = ['Albania', 'Andorra', 'Armenia', 'Austria',
'Azerbaijan', 'Belarus', 'Belgium', 'Bosnia and Herzegovina', 'Bulgaria',
'Croatia', 'Cyprus', 'Czech Republic', 'Denmark', 'Estonia', 'Finland',
'France', 'Georgia', 'Germany', 'Greece', 'Hungary', 'Iceland', 'Ireland',
'Italy', 'Kazakhstan', 'Kosovo', 'Latvia', 'Liechtenstein', 'Lithuania',
'Luxembourg', 'Macedonia', 'Malta', 'Moldova', 'Monaco', 'Montenegro',
'Netherlands', 'Norway', 'Poland', 'Portugal', 'Romania', 'Russia',
'San Marino', 'Serbia', 'Slovakia', 'Slovenia', 'Spain', 'Sweden',
'Switzerland', 'Turkey', 'Ukraine', 'United Kingdom', 'Vatican City'];

return ListView.builder(
itemCount: countries.length,
itemBuilder: (ctx,index){
return ListTile(
onTap: (){

_scaffoldKey.currentState.showSnackBar(SnackBar(content:
Text("Clicked on Country ${countries[index]}")));
47

},
title: Text(countries[index]),
leading: Icon(Icons.flag),
trailing: Icon(Icons.arrow_forward_ios,size: 14,),
);
});
}
}

Listview.separated

class ListViewBuilderWidget extends StatefulWidget{

@override
48

State<StatefulWidget> createState() {
return new _ListViewBuilderWidget ();
}

}


class _ListViewBuilderWidget extends
State<ListViewBuilderWidget>{

@override
Widget build(BuildContext context) {
return Scaffold(

appBar: new AppBar(
title: new Text( "ListviewBuilder Widget" ),
),

body: ListView.separated(
itemCount: 100 ,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text( " $index - " , style: TextStyle(color:
Colors. blue ),));
},

separatorBuilder: (BuildContext context, int index) {
return Divider(color: Colors. blue , height: 10 ,);
}
),
);
}

}


49

Examples of Single Child Layout Widgets
Container
A convenience widget that combines common painting,
positioning, and sizing widgets. Often used to contain
wrap child widgets and apply styling

Container having the below properties
Color Property
Child Property
Alignment Property
Constraints Property
Margin Property
Padding Property
Decoration Property
ForegroundDecoration Property
Transform Property


class ContainerWidget extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text( "Container" ),),
body: Container(
color: Color.fromARGB( 255 , 66 , 165 , 245 ),
child: Container(
color: Colors. pink ,
alignment: Alignment. center ,
constraints: BoxConstraints(
maxHeight: 300 ,
50

maxWidth: 200 ,
minWidth: 150 ,
minHeight: 150 ,
),
child: Container(
child: Text( "Flutter Cheatsheet" ,
style: TextStyle(
fontSize: 30.0 ,
color: Colors. white ,
),),),
transform: Matrix4.rotationZ( 0.5 ),
),
alignment: Alignment. center ,
),),);
}}



51

Card
A card-like widget. Similar to Android's CardView, the card has slightly
rounded corners and shadows

Card Widget attribute

color : container background color
elevation : Z-axis height, to achieve the shadow effect.
shape : defines the shape of the container
margin : margin
clipBehavior : the way to clip content

Example:

class CardWidget extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
appBar: AppBar(title:Text( "Card Widget" ),backgroundColor:
Colors. pink ,),
body: Container(
alignment: Alignment. topCenter ,
margin: EdgeInsets.only(top: 10.0 ),
child: SizedBox(
width: 400.0 ,
height: 200.0 ,
child: Card(
color: Colors. purple ,
elevation: 30.0 ,
child: Padding(
padding: EdgeInsets.all(
14.0 ,
52

),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
CircleAvatar(

backgroundImage: NetworkImage(

"https://cdn.pixabay.com/photo/2016/10/17/17/41/priyan
ka-chopra-1748248_960_720.jpg" ),
radius: 24.0 ,
),
Container(
margin: EdgeInsets.only(left: 10.0 ),
child: Text(
"Text" ,
style:
TextStyle(color: Colors. white , fontSize: 20.0 ),
),
),
],
),
Container(
margin: EdgeInsets.only(top: 30.0 ),
child: Text(
"Never Stop Thinking..." ,
style: TextStyle(color: Colors. white , fontSize: 30.0 ),
),
),
Container(
alignment: Alignment. bottomRight ,
margin: EdgeInsets.only(top: 30.0 ),
child: Text(
"2020-01-10 15:47:35" ,
style: TextStyle(color: Colors. white , fontSize: 14.0 ),
),
),
53

],
),
),
),
),
),
),
);
}

}



Expanded
The Expanded component allows Row, Column, Flex and other
sub-components to expand in the direction of their main axis and fill the
available space. Similar usage of widget properties in Android
54

●Expanded will be distributed as full as possible in the main axis
direction of Row, Column, or Flex
●If Column contains two childs and two widgets are expanded, both
share the
available vertical space evenly.
●If only one is expanded, the expanded one takes up
all the available vertical space.
●If neither is expanded, the available vertical space
goes unfilled


Example:


class ExpandedWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
appBar: AppBar(backgroundColor: Colors. pink ,title:
Text( "Expanded Widget" ),),
body: new Row(
children: <Widget>[
new Expanded(
flex: 2 ,
child: new Container(
child: new Text( 'Text1' , textAlign: TextAlign. center ),
height: 100 ,
alignment: AlignmentDirectional. center ,
color: Colors. yellow ,
),
),
new Expanded(
55

flex: 1 ,
child: new Container(
child: new Text( 'Text2' , textAlign: TextAlign. center ),
height: 100 ,
alignment: AlignmentDirectional. center ,
color: Colors. lightGreen ,
),
),
new Expanded(
flex: 1 ,
child: new Container(
child: new Text( 'Text3' , textAlign: TextAlign. center ),
height: 100 ,
alignment: AlignmentDirectional. center ,
color: Colors. deepPurple ,
),
),
],
),
));
}
}


56

Flexible
It is actually Expanded inheritance Flexible. Use Flexible widgets to Row,
Column or Flex provided in the main shaft expands to fill the available
space in flexibility (e.g., horizontal filling sub assembly Row or
perpendicular filled Column), but Expandeddifferent, Flexible is not
required to fill the available space sub components.

Flexible The control must be Row, Column or Flex a descendant of Row, the
path from the control to its closure , Column or Flex the path must contain
only Stateless Widgets or Stateful Widget these, and cannot be other types
of widgets (for example Render ObjectWidget)

57

Center
This widget is used to center a Widget within its parent
Widget.

GestureDetector

GestureDetector is a widget that detects gestures. If the child property of
GestureDetector is not empty, GestureDetector sets its size to the size of the
child.
If the child property is empty, it sets its size to the size of the parent
component
We have different type of gestures, below are few of them

●onTapDown,
●onTapUp,
●onTap,
●onTapCancel,
●onForcePressPeak,
●onForcePressUpdate,
●onForcePressEnd,
●onPanDown,
●onPanStart,
●onPanUpdate,
●onPanEnd,
●onPanCancel,
●onScaleStart,
●onScaleUpdate,
●onScaleEnd
58

●onSecondaryTapDown,
●onSecondaryTapUp,
●onSecondaryTapCancel,
●onDoubleTap,
●onLongPress,
●onLongPressStart,
●onLongPressMoveUpdate,
●onLongPressUp,
●onLongPressEnd,

Example

class GesterDetectorWidget extends StatelessWidget{
GlobalKey<ScaffoldState> _scaffoldstate =GlobalKey();
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
key: _scaffoldstate ,
appBar: AppBar(title:Text( "Card Widget" ),backgroundColor:
Colors. pink ,),
body: Container(
child: GestureDetector(

child: Center(


child: Container(
color: Colors. pink ,
child: Padding(
padding: const EdgeInsets.all( 8.0 ),
child: Text( "Gesture Me" ,style: TextStyle(fontSize:
20 ,color: Colors. white ),),
),
)),
59

onTap: (){

_scaffoldstate . currentState .showSnackBar(SnackBar(content:
Text( "onTap Event" )));
},
onDoubleTap: (){

_scaffoldstate . currentState .showSnackBar(SnackBar(content:
Text( "onDoubleTap Event" )));
},
onLongPress: (){

_scaffoldstate . currentState .showSnackBar(SnackBar(content:
Text( "onLongPress Event" )));
},
),
)
)
);
}

}




60

Positioned
This use controls the position of the widget, through which he can place a
component at will, a bit like an absolute layout
Positioned({
Key key,
this.left,
this.top,
this.right,
this.bottom,
this.width,
this.height,
@required Widget child,
})

61

Example

class PositionedWidget extends StatelessWidget{
GlobalKey<ScaffoldState> _scaffoldstate =GlobalKey();
@override
Widget build(BuildContext context) {
final size = MediaQuery. of (context). size ;
return MaterialApp(
home: Scaffold(
key: _scaffoldstate ,
appBar: AppBar(title:Text( "Positioned
Widget" ),backgroundColor: Colors. pink ,),
body:Container(
width: size. width ,
height: size. height ,
child: Stack(
children: <Widget>[
Positioned(
child: CircleAvatar(
backgroundImage:
NetworkImage( "https://cdn.pixabay.com/photo/2016/10/17/17/4
1/priyanka-chopra-1748248_960_720.jpg" ),
radius: 80.0 ,
),
right: 10 , top: 10 ,
),
Positioned(
child: CircleAvatar(
backgroundImage:
NetworkImage( "https://cdn.pixabay.com/photo/2016/10/17/17/4
1/priyanka-chopra-1748248_960_720.jpg" ),
radius: 80.0 ,
),
left: size. width / 2 * 0.8 ,
top: size. height / 2 * 0.7 ,
62

),
Positioned(
child: CircleAvatar(
backgroundImage:
NetworkImage( "https://cdn.pixabay.com/photo/2016/10/17/17/4
1/priyanka-chopra-1748248_960_720.jpg" ),
radius: 80.0 ,
),
left: 10 ,
bottom: 10 ,
)],
), ),) );
}}

63

SafeArea

A widget that insets its child by sufficient padding to avoid intrusions by
the operating system

SafeArea is mainly used to ensure that the view will not be covered by
system components, such as the status bar, etc
SafeArea Constructor is like below

const SafeArea({
Key key,
this . left = true ,
this . top = true ,
this . right = true ,
this . bottom = true ,
this . minimum = EdgeInsets. zero ,
this . maintainBottomViewPadding = false ,
@required this . child ,
})


SingleChildScrollView
This Widget is used to show a child Widget even if there is not enough
space to view the entirety of the child Widget

SingleChildScrollView is similar to scrollview in Android, and it can only
contain one child element

const SingleChildScrollView({
Key key,
this.scrollDirection = Axis.vertical,
64

this.reverse = false,
this.padding,
bool primary,
this.physics,
this.controller,
this.child,
this.dragStartBehavior = DragStartBehavior.down,
})

key : the unique identifier of the current element (similar to id in Android)
scrollDirection : scroll direction, default is vertical
reverse : whether to slide in the opposite direction of the reading
direction.
padding : padding distance
primary : Whether to use the default Primary ScrollController in the
widget tree. When the sliding direction is vertical (scrollDirection value is
Axis.vertical) and the controller is not specified, the primary defaults to
true
physics : This property accepts a ScrollPhysics object, which determines
how the scrollable widget responds to user operations, such as the user
continuing to perform an animation after lifting the finger, or how to
display it when sliding to the boundary.
controller : This property accepts a ScrollController object. The main role
of ScrollController is to control the scroll position and listen for scroll
events
child : child element

class SingleChildScrollViewWidget extends StatelessWidget{
var alphabets = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
65

appBar: AppBar(title:Text( "SingleChildScroll
Widget" ),backgroundColor: Colors. pink ,),
body: horizontalScroll()
));
}


horizontalScroll()
{
return SingleChildScrollView(
scrollDirection: Axis. horizontal ,
child: Center(
child: Row(
children: alphabets .split( "" ).map((a)=>Padding(
padding: const EdgeInsets.all( 8.0 ),
child: Text(a,style: TextStyle(fontSize: 20 ,color:
Colors. pink ),),
)).toList(),
),
),
);
}
verticalScroll()
{
return SingleChildScrollView(
scrollDirection: Axis. vertical ,
child: Center(
child: Column(
children: alphabets .split( "" ).map((a)=>Padding(
padding: const EdgeInsets.all( 8.0 ),
child: Text(a,style: TextStyle(fontSize: 20 ,color:
Colors. pink ),),
)).toList(),
),
),
);
}
}
66

Vertical Direction Horizontal Direction


Themes
When we build a Flutter app, we build a root Widget. That Widget usually
returns a MaterialApp, which builds the foundations for the app. One of the
constructor arguments for MaterialApp is the Theme object. This object
specifies the colors to be used in the application’s Widgets. As you can see
below the user can pass in Theme data into the MaterialApp constructor
using a ThemeData object

Change Dynamic theme
Find example here http://rrtutors.com/description/27
67

Scaffold
Scaffold is the page display framework
Scaffold has different attributes to handle the Pages

appBar: An AppBar displayed at the top of the interface, which is the
ActionBar and Toolbar in Android
body: the main content widget displayed in the current interface
floatingActionButton: FAB defined in paper and ink design, the main
function button of the interface
persistentFooterButtons: Buttons that are fixed to the bottom, such as
OK and Cancel buttons below the dialog box
drawer: sidebar control
backgroundColor: The background color of the content. The default
value is ThemeData.scaffoldBackgroundColor.
bottomNavigationBar: the navigation bar displayed at the bottom of the
page

resizeToAvoidBottomPadding: similar to
android: windowSoftInputMode = ”adjustResize” in Android,
controls whether the content body of the interface is rearranged to avoid
the bottom being covered, for example, when the keyboard is displayed, the
re-layout is to avoid covering the content with the keyboard. The default
value is true


class ScffoldHomePage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return ScffoldHomePageState();
}
}
68

class ScffoldHomePageState extends State<ScffoldHomePage> {

num index = 0 ;


List <Widget> pageWidgetList =[
Home(),
SearchScreen(),
ProfileScreen(),
];

@override
Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(
title: Text( "HomePage" ),
backgroundColor: Colors. pink ,
),

body: pageWidgetList [ index ],

floatingActionButton: FloatingActionButton(
child: Text( "++" ),

onPressed: () {

},

tooltip: "Click tooltips" ,

backgroundColor: Colors. pink ,

focusColor: Colors. green ,

hoverColor: Colors. purpleAccent ,
69

splashColor: Colors. deepPurple ,

foregroundColor: Colors. white ,

elevation: 0.0 ,

highlightElevation: 20.0 ,
),

floatingActionButtonLocation:
FloatingActionButtonLocation. endFloat ,

persistentFooterButtons: <Widget>[
Text(
"1" ,
style: TextStyle(color: Colors. blue ),
),
Text( "2" ),
Text( "3" ),
Text( "4" ),
Text( "5" ),
],

drawer: Container(
color: Colors. grey ,
width: 120 ,
child: FlatButton(
child: Text( "Close Left Swipe" ),
onPressed: () {
Navigator. of (context).pop();
},
),
),

endDrawer: Container(
color: Colors. orange ,
width: 200 ,
70

height: 800 ,
child: FlatButton(
child: Text( "Close Right Swipe" ,style: TextStyle(color:
Colors. white ),),
onPressed: () {
Navigator. of (context).pop();
},
),
),

bottomNavigationBar: new BottomNavigationBar(

backgroundColor: Colors. pink ,
items: <BottomNavigationBarItem>[

BottomNavigationBarItem(icon:Icon(Icons. home ,color:
index == 0 ?Colors. white :Colors. white ,),title: Text( "Home" ,style:
TextStyle(color: index == 0 ?Colors. white :Colors. white ),) ),
BottomNavigationBarItem(icon:Icon(Icons. search ,color:
index == 1 ?Colors. white :Colors. white ,),title: Text( "Search" ,style:
TextStyle(color: index == 1 ?Colors. white :Colors. white ),) ),
BottomNavigationBarItem(icon:Icon(Icons. people ,color:
index == 2 ?Colors. white :Colors. white ,),title:
Text( "Account" ,style: TextStyle(color:
index == 2 ?Colors. white :Colors. white ),) ),
],
onTap: (flag) {
print( "flag $flag " );
index = flag;
setState(() {});
},
currentIndex: index ,
) ,
);
}
}

71

72

Dialogs
A material design dialog, Dialogs are temporary windows that appear as
overlays over the existing application

Show dialog is simple

showDialog(context: context,
builder: (context) => Center(child: Text("Dialog")));

In flutter we have multiple ways to show dialogs
1.Alert Dialog
2.Custom Dialog
3.Full-Screen Dialog

Simple AlertDialog

showDialog(
context: context,
builder: (BuildContext context){
return AlertDialog(
title: Text("Alert Dialog"),
content: Text("Dialog Content"),
);
}
)


This is a simple alert dialog with title and message. We can also add buttons
to handle the events

73

Add buttons to Alert Dialogs
This widget, there is a parameter called action. It accepts an array of
widgets and we can provide multiple buttons to that.
Those Buttons will appear in the bottom right corner of the dialog

actions:[
FlatButton(
child: Text("Close"),
)
]


How to close Dialog
We can close the Displayed Dialog by calling the
Navigator.of(context).pop();

FlatButton(
child: Text("Close"),
onPressed: (){
Navigator.of(context).pop();
},
)

Example

class MyDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text( "Dialog" ),backgroundColor:
Colors. pink ,),
body: Center(
74

child: FlatButton(
onPressed: () {
showMyDialog(context);
},
child: Text(
'Show Me' ,
style: TextStyle(
fontSize: 16.0 ,
fontWeight: FontWeight. bold ,
color: Colors. white ),
),
color: Colors. pink ,
),
),
);
}
void showMyDialog(BuildContext context) {
showDialog(
context: context,
barrierDismissible: false ,
builder: (BuildContext context) {
return Dialog(
child: _contentWidget(context),
insetAnimationCurve: Curves. fastOutSlowIn ,
insetAnimationDuration: Duration(milliseconds: 100 ),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular( 8.0 ),
), ),);
});
}
Widget _contentWidget(BuildContext context) {
return Center(
widthFactor: 2.0 ,
heightFactor: 1.0 ,
child: Container(
width: 300.0 ,
height: 200.0 ,
75

color: Colors. white ,
child: Column(
children: <Widget>[
Expanded(
child: Container(
padding: EdgeInsets.only(top: 5.0 ),
child: Text( 'This is title' ,style: TextStyle(color:
Colors. black ,fontWeight: FontWeight. bold ,fontSize: 22.0 ),),),
flex: 1 ,
),
Expanded(
child: Container(
alignment: Alignment. topLeft ,
margin: EdgeInsets.all( 20.0 ),
child: Text( 'Text Message to display the Dialog in
Flutter' ,style: TextStyle(fontSize: 18.0 ,color: Colors. black ),),
),
flex: 3 ,
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment. spaceEvenly ,
children: <Widget>[
RaisedButton(onPressed: (){
Navigator. of (context).pop();
},
child: Text( 'Continue' ,style: TextStyle(color:
Colors. white )),color: Colors. pink ,),
FlatButton(onPressed: (){
Navigator. of (context).pop();
},
child: Text( 'Cancel' ,style: TextStyle(color:
Colors. pink ),)),
],
),
flex: 2 ,
),
],
76

),
),
);
}
}




77

ExpansionPanelList & ExpansionPanel
These two widgets are designed to work together to present a list of
expandable panels to the user
We have to manage the state of what was expanded / collapsed and rebuild
the ExpansionPanelList & ExpansionPanels everytime the state changes

ExpansionPanel
Shrink the panel. It has a title and a body that can be expanded or
collapsed. The body of the panel is only visible when expanded.
The shrink panel is only used as a child of ExpansionPanelList. Example
implementation, please use ExpansionPanelList

ExpansionPanel({
@required this.headerBuilder,
@required this.body,
this.isExpanded = false,
this.canTapOnHeader = false,
})

ExpansionPanelList
A material expansion panel list that lays out its children and animates
expansions
Lays out the child ExpansionPanels

const ExpansionPanelList({
Key key,
this.children = const <ExpansionPanel>[],
this.expansionCallback,
this.animationDuration = kThemeAnimationDuration,
})
78

There are only three parameters that we need to use:

children : Needless to say, it is ExpansionPanel
expansionCallback : expansion callback, here will return the index of the
click
animationDuration : the duration of the animation

Example:

class ExpansionWidget extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return ExpansionWidgetState();
}

}
class ExpansionWidgetState extends State<ExpansionWidget>{
List<bool> listExpans =List();

@override
void initState() {
// TODO: implement initState
super .initState();
listExpans .add( false );
listExpans .add( false );
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
backgroundColor: Colors. grey ,
appBar: AppBar(title:
Text( "Expansionpanel" ),backgroundColor: Colors. pink ,),
body: SingleChildScrollView(
child: Container(
79

alignment: Alignment. center ,
child: Column(
children: <Widget>[
ExpansionPanelList(
children : <ExpansionPanel>[
ExpansionPanel(
headerBuilder:(context, isExpanded){
return ListTile(
title: Text( 'Try Expansion 1' ),
);
},
body: Padding(
padding: EdgeInsets.fromLTRB( 15 , 0 , 15 , 15 ),
child: ListBody(
children: <Widget>[
Card(
margin:EdgeInsets.fromLTRB( 0 , 0 , 0 , 10 ),
child: Padding(padding: EdgeInsets.all( 8 ),child:
Text( 'Content 1' ),),
),
Card(
margin:EdgeInsets.fromLTRB( 0 , 0 , 0 , 10 ),
child: Padding(padding: EdgeInsets.all( 8 ),child:
Text( 'Content 2' ),),
),
Card(
margin:EdgeInsets.fromLTRB( 0 , 0 , 0 , 10 ),
child: Padding(padding: EdgeInsets.all( 8 ),child:
Text( 'Content 3' ),),
),
Card(
margin:EdgeInsets.fromLTRB( 0 , 0 , 0 , 10 ),

child: Padding(padding: EdgeInsets.all( 8 ),child:
Text( 'Content 4' ),),
),
Card(
margin:EdgeInsets.fromLTRB( 0 , 0 , 0 , 10 ),
80

child: Padding(padding: EdgeInsets.all( 8 ),child:
Text( 'Content 5' ),),
),
],
),
),
isExpanded: listExpans [ 0 ],
canTapOnHeader: true ,
),

ExpansionPanel(

headerBuilder:(context, isExpanded){
return ListTile(
title: Text( 'Try Expansion 2 ' ),
);
},
body: Padding(
padding: EdgeInsets.fromLTRB( 15 , 0 , 15 , 15 ),
child: ListBody(
children: <Widget>[
Card(
margin:EdgeInsets.fromLTRB( 0 , 0 , 0 , 10 ),
child: Padding(padding: EdgeInsets.all( 8 ),child:
Text( 'Content 1' ),),
),
Card(
margin:EdgeInsets.fromLTRB( 0 , 0 , 0 , 10 ),
child: Padding(padding: EdgeInsets.all( 8 ),child:
Text( 'Content 2' ),),
),
Card(
margin:EdgeInsets.fromLTRB( 0 , 0 , 0 , 10 ),
child: Padding(padding: EdgeInsets.all( 8 ),child:
Text( 'Content 3' ),),
),
Card(
margin:EdgeInsets.fromLTRB( 0 , 0 , 0 , 10 ),
81

child: Padding(padding: EdgeInsets.all( 8 ),child:
Text( 'Content 4' ),),
),
Card(
margin:EdgeInsets.fromLTRB( 0 , 0 , 0 , 10 ),
child: Padding(padding: EdgeInsets.all( 8 ),child:
Text( 'Content 5' ),),
),
],
),
),
isExpanded: listExpans [ 1 ],
canTapOnHeader: true ,
),

],
expansionCallback:(panelIndex, isExpanded){
setState(() {
listExpans [panelIndex] = !isExpanded;
});
},
animationDuration : kThemeAnimationDuration,
),
],
),
),
)
);


}

}




82

GridView
GridView displays the values of a data source in a table where each column
represents a field and each row represents a record

Constructors
GridView.builder()
GridView.count()
GridView.custom()
GridView.extent()


83

GridView.builder({
Key key,
Axis scrollDirection = Axis. vertical ,
bool reverse = false ,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap = false ,
EdgeInsetsGeometry padding,
@required this . gridDelegate ,
@required IndexedWidgetBuilder itemBuilder,
int itemCount,
bool addAutomaticKeepAlives = true ,
bool addRepaintBoundaries = true ,
bool addSemanticIndexes = true ,
int semanticChildCount,
})


Example

class GridViewWidget extends StatelessWidget {
List list = new List();
GridViewWidget() {
for (int i = 1 ; i < 20 ; i++) {
int j = (i % 9 ) + 1 ;
var temp = {
"imageurl" :
"https://cdn.pixabay.com/photo/2016/10/17/17/41/priyan
ka-chopra-1748248_960_720.jpg" ,
"title" : "Image $i "
};
list .add(temp);
}
}
@override
Widget build(BuildContext context) {
84

// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text( "GridView" ),
backgroundColor: Colors. pink ,
),
body: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3 ,
mainAxisSpacing: 5 ,
crossAxisSpacing: 5 ,
),
itemCount: list . length ,
itemBuilder: (BuildContext context, int index) {
return Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors. red ,
width: 2 ,
)),
child: Column(
mainAxisSize: MainAxisSize. max ,
mainAxisAlignment: MainAxisAlignment. end ,
children: <Widget>[
Image.network(
list [index][ 'imageurl' ],
fit: BoxFit. cover ,
),
Expanded(child: Text( list [index][ 'title' ])),
],
),
);
}));
}
}
85

PopupMenu

Why use this PopupMenu? Because most message interfaces have a setting option in the
upper right corner, and this option is most commonly implemented through PopupMenu.

Look at the effect map

86

class PopupWidget extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return PopupWidgetState();
}

}

class PopupWidgetState extends State<PopupWidget>
{
int _value = 1 ;

@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(title: Text( "Popup
Window" ),backgroundColor: Colors. pink ,

actions: <Widget>[
_NomalPopMenu()
],),
body: Container(
child: Center(
child: Container(
decoration:ShapeDecoration(shape: OutlineInputBorder(

)),
width: 200 ,
height: 40 ,
child: Center(child: Text( "Value selected $ _value " ,style:
TextStyle(color: Colors. pink ,fontSize: 20 ),)),
),
),
),
);
87

}
Widget _NomalPopMenu() {
return new PopupMenuButton<int>(
itemBuilder: (BuildContext context) =>
<PopupMenuItem<int>>[
new PopupMenuItem<int>(
value: 1 , child: new Text( 'Item One' )),
new PopupMenuItem<int>(
value: 2 , child: new Text( 'Item Two' )),
new PopupMenuItem<int>(
value: 3 , child: new Text( 'Item Three' )),
new PopupMenuItem<int>(
value: 4 , child: new Text( 'I am Item Four' ))
],
onSelected: (int value) {
setState(() { _value = value; });
});
}
}




Checked Widgets
CheckBox
Checkbox is a checkbox component, usually used for setting options

Attributes
●activeColor : Color -the color when active.
●onChanged : ValueChanged -fired when changed.
●tristate: bool -If true, the value of the checkbox can be true, false or
null.
88

●value : bool -the value of the checkbox


CheckboxListTile
CheckboxListTile is an upper-level package of Checkbox. Its appearance is
to provide a selection component similar to a setting page, which can set
icons and text

Radio
Radio is used for single selection options

Attributes
●Value of value radio
●groupValue radio The value of the group. Value == groupValue is
selected.
●onChanged callback when the value changes
●activeColor when selected

Example

class CheckWidgets extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return CheckWidgetState();
}

}

class Course{
Course( this . title , this . price , this . courseCheck );
89

bool courseCheck ;
String title ;
double price ;
}
class CheckWidgetState extends State<CheckWidgets>
{
int priceCheck = 0 ;
String doller_rupee = "Rs" ;

List<Course> listCourse =List();
@override
void initState() {
// TODO: implement initState
super .initState();

listCourse .add(Course( "Course 1" , 699 , false ));
listCourse .add(Course( "Course 2" , 693 , false ));
}

@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(

appBar: AppBar(title: Text( "Checked
Widgets" ),backgroundColor: Colors. pink ,),
body: Container(
margin: EdgeInsets.all( 10 ),

child: Column(
children: <Widget>[

Card(
child: Padding(
padding: const EdgeInsets.all( 8.0 ),
child: Column(
children: <Widget>[
Row(
90

children: <Widget>[
Text( "Price in " ,style: TextStyle(color:
Colors. pink ,fontSize: 22 ),),

],
),
Row(
children: <Widget>[
Row(
children: <Widget>[
Radio(
value: 0 ,
activeColor: Colors. pink ,
groupValue: priceCheck ,
onChanged: (newValue) {
setState(() {
priceCheck = newValue;
doller_rupee = "Rs" ;
});
}
),
Text( 'Rupee' )
],
),
Row(
children: <Widget>[
Radio(
value: 1 ,
activeColor: Colors. pink ,
groupValue: priceCheck ,
onChanged: (newValue) {
setState(() {
priceCheck = newValue;
doller_rupee = " \$ " ;
});
}
),
Text( 'Dollar' )
91

],
),

],
),
],
),
),
) ,
Card(
child: Padding(
padding: const EdgeInsets.all( 8.0 ),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text( "Select Course" ,style: TextStyle(color:
Colors. pink ,fontSize: 24 ),),

],
),
ListView.builder(
shrinkWrap: true ,
itemCount: listCourse . length ,
itemBuilder: (ctx,pos){
return Column(
children: <Widget>[
CheckboxListTile(
subtitle: Text( " $ doller_rupee
${ listCourse [pos]. price } " ,style: TextStyle(fontSize: 16 ,color:
Colors. green ),),
title: Text( listCourse [pos]. title ,style:
TextStyle(fontSize: 22 ,color: Colors. black ),),
checkColor:Colors. white , activeColor:Colors. pink ,
value: this . listCourse [pos]. courseCheck ,
onChanged: (bool value) {
setState(() {
listCourse [pos]. courseCheck =
92

! listCourse [pos]. courseCheck ;
});
},
),
Divider(height: 2 ,color: Colors. pink ,)
],
);
})
],
),
),
),],
),

),
);
}

}


93

94

TabBar TabBarView
TabBar is a row of horizontal tabs, you can switch back and forth, the effect
map

TabBar is generally used together with TabBarView.
TabBarView is used to select different TabBars.
TabBarView displays the corresponding View
TabBarView property description


class TabBarDemo extends StatefulWidget {
@override
State<StatefulWidget> createState() => _TabBar();
}

class _TabBar extends State<TabBarDemo> {
final List<String> _tabValues = [
'Tab1' ,
'Tab2' ,
'Tab3' ,
'Tab4' ,
'Tab5' ,
'Tab6' ,
'Tab7' ,
'Tab8' ,
];

TabController _controller ;

@override
void initState() {
super .initState();
_controller = TabController(
length: _tabValues . length ,
95

vsync: ScrollableState(),
);
}

@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
backgroundColor: Colors. pink ,
title: Text( 'TabBar' ),
bottom: TabBar(
tabs: _tabValues .map((f) {
return Text(f,style: TextStyle(fontSize: 20 ),);
}).toList(),
controller: _controller ,
indicatorColor: Colors. grey ,

isScrollable: true ,
labelColor: Colors. white ,
unselectedLabelColor: Colors. white54 ,
indicatorWeight: 5.0 ,
labelStyle: TextStyle(height: 2 ),
),
),
body: TabBarView(
controller: _controller ,
children: _tabValues .map((f) {
return Center(
child: Text(f,style: TextStyle(fontSize: 80 ,color:
Colors. pink ),),
);
}).toList(),
),
);
}
}

96

Table
A widget that uses the table layout algorithm for its children
The height of each row of the table is determined by its content, and the
width of each column is controlled individually by the columnWidths
property





97

class TableWidget extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(title: Text( "Table Widget" ),backgroundColor:
Colors. pink ,),
body: Container(
child: Padding(
padding: const EdgeInsets.all( 8.0 ),
child: Card(
child: Table(
columnWidths: const <int, TableColumnWidth>{
0 : FixedColumnWidth( 50.0 ),
1 : FixedColumnWidth( 100.0 ),
2 : FixedColumnWidth( 50.0 ),
3 : FixedColumnWidth( 100.0 ),
},

border: TableBorder.all(color: Colors. pink , width: 1.0 , style:
BorderStyle. solid ),
children: const <TableRow>[

TableRow(
children: <Widget>[
Center(child: Text( 'A1' ,style: TextStyle(fontSize: 18 ),)),
Center(child: Text( 'B1' ,style: TextStyle(fontSize: 18 ),)),
Center(child: Text( 'C1' ,style: TextStyle(fontSize: 18 ),)),
Center(child: Text( 'D1' ,style: TextStyle(fontSize: 18 ),)),
],
),
TableRow(
children: <Widget>[
Center(child: Text( 'A2' ,style: TextStyle(fontSize: 18 ),)),
Center(child: Text( 'B2' ,style: TextStyle(fontSize: 18 ),)),
Center(child: Text( 'C2' ,style: TextStyle(fontSize: 18 ),)),
Center(child: Text( 'D2' ,style: TextStyle(fontSize: 18 ),)),
],
98

),
TableRow(
children: <Widget>[
Center(child: Text( 'A3' ,style: TextStyle(fontSize: 18 ),)),
Center(child: Text( 'B3' ,style: TextStyle(fontSize: 18 ),)),
Center(child: Text( 'C3' ,style: TextStyle(fontSize: 18 ),)),
Center(child: Text( 'D3' ,style: TextStyle(fontSize: 18 ),)),
],
),
],
),
),
)
,
),
);
}

}


99

100

Future and FutureBuilder
To Make the Asynchronous operation will use Future

Uses
future.then get future value and catch future exception Combined
async,await
future.whenComplete
future.timeout


import 'dart:async';
Future<String> testFuture() {
// throw new Error();
return Future.value('success');
// return Future.error('error');
}

main() {
testFuture().then((s) {
print(s);
}, onError: (e) {
print('onError:');
print(e);
}).catchError((e) {
print('catchError:');
print(e);
});
}


Sometimes we need to Futuredo something at the end, and we know
then().catchError()the pattern is similar try-catch, try-catch there is a
finally code block, and future.whenCompletethat Future Is finally
101

FutureBuilder
FutureBuilder combines asynchronous operations and asynchronous UI
updates. Through it we can update the results of network requests,
database reads, etc.
future : Future object represents the asynchronous calculation currently
connected to this builder;
initialData : Indicates the initialization data of a non-empty Future before
completion;
builderA return function of type AsyncWidgetBuilder is a function that
builds a widget based on asynchronous interaction

Properties
connectionState -Enumeration of ConnectionState, which indicates the
connection status with asynchronous calculation. ConnectionState has four
values: none, waiting, active, and done;

data -Asynchronous calculation of the latest data received;
error -Asynchronously calculate the latest error object received;

Example

class FutureWidget extends StatefulWidget {
String computeListOfTimestamps(int count) {
StringBuffer sb = new StringBuffer();

var random = Random();

for (int i = 0 ; i < 2000 ; i++) {
sb.writeln( "Random Number : ${random.nextInt( 2000 )} " );
sb.writeln( "" );
}
return sb.toString();
}
102

Future<String> createFutureCalculation(int count) {
return new Future(() {
return computeListOfTimestamps(count);
},);
}



@override
FutureWidgetState createState() => new FutureWidgetState();
}

class FutureWidgetState extends State<FutureWidget> {
bool _showCalculation = false ;
bool isLoading = false ;
GlobalKey<ScaffoldState> _scaffoldKey =GlobalKey();

void _onInvokeFuturePressed() {
setState(() {
_showCalculation = ! _showCalculation ;
isLoading = true ;

});
}

@override
Widget build(BuildContext context) {
Widget child = _showCalculation
? FutureBuilder(
future: widget .createFutureCalculation( 1000 ),

builder: (BuildContext context, AsyncSnapshot snapshot) {
return Expanded(
child: SingleChildScrollView(
child: (snapshot. data == null )?Center(child:
CircularProgressIndicator()):Text(
' ${snapshot. data == null ? "" : snapshot. data } ' ,
103

style: TextStyle(fontSize: 20.0 ))));
})
: Text( 'Press Refresh to load Data' );
return new Scaffold(
key: _scaffoldKey ,
appBar: new AppBar(
backgroundColor: Colors. pink ,
title: new Text( "Future Builder " ),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment. center ,
children: <Widget>[child])),
floatingActionButton: new FloatingActionButton(
backgroundColor: Colors. pink ,
onPressed: _onInvokeFuturePressed,
tooltip: 'Call Future' ,
child: new Icon(Icons. refresh ),
), // This trailing comma makes auto-formatting nicer for build
);
}
}



104

StreamBuilder

StreamBuilder is similar to FutureBuilder, provides the ability to acquire
asynchronous data and update ui

Stream is an event stream, which is similar to RxJava. It allows us to emit
an event from one end and listen to changes in the event from the other
105

end. Through Stream we can design reactive code based on event flow on
Flutter logic
Stream is not flutter widget, it provided by Dart
Stream is an abstract interface

StreamBuilder Constructor

const StreamBuilder({
Key key,
this . initialData ,
Stream<T> stream,
@required this . builder ,
})


Example

class StreamBuilderWidget extends StatelessWidget{
var index = 0 ;
StreamSubscription<String> subscription ;

var streamController = StreamController<String>();

//To Emit the stream
StreamSink<String> get streamSink =>
streamController . sink ;

Stream<String> get streamData =>
streamController . stream ;

StreamBuilderWidgetState()
{
streamSink .add( "0" );
}


106

void onFloatActionButtonPress() {

streamSink .add( index .toString());
index ++;
}


@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(title: Text( "Stream
Builder" ),backgroundColor: Colors. pink ,),
body: Center(
child: StreamBuilder<String>(
stream: streamData ,
builder: (BuildContext context, AsyncSnapshot<String>
snapshot) {
return Text( 'Result: ${snapshot. data } ' );
}
)
),
floatingActionButton: FloatingActionButton(
onPressed: onFloatActionButtonPress,
child: Icon(Icons. add ))

);

}

}





107

Navigation

To Implement page navigation in Flutter we need to use two classes
Navigator and Route.

The Navigator is responsible for the stack structure processing of the page
and the route processing of the Route complex page

The Navigator used the stack structure to manage pages.
When a page needs to be added, the stack method is used, when we need to
exit a page use the pop-out method

Push and pop will handle all stack elements

Let’s Start Code

Create Two Pages
First, we will create two pages, each of which contains a button. Clicking the
button on the first page will jump to the second page, and clicking the
button on the second page will return to the first page

class FirstPage extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(title: Text( " First Page" ), backgroundColor:
Colors. pink ,),
body: Center(
child: RaisedButton(
onPressed: (){

108

},
child: Text( "Second Page" , style: TextStyle(color:
Colors. white ),),
color: Colors. pink ,
),
),
);
}

}


class SeconPage extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(title: Text( " Second Page" ), backgroundColor:
Colors. pink ,),
body: Center(
child: RaisedButton(
onPressed: (){

},
child: Text( "Navigate to First Page" , style: TextStyle(color:
Colors. white ),),
color: Colors. pink ,
),
),
);
}

}




109

Now let’s jump to second page

In order to jump to the second page, we will use the Navigator.push
method. This push method will add one Route to the routing heap managed
by Navigator.
But the Push method requires one Route, but Route where does it come
from? We can create our own Route, or use it MaterialPageRoute.
MaterialPageRoute Conveniently, it will jump to a new page using
platform-specific animations.
In the FirstScreen Widget build method, update the onPressedcallback

onPressed: () {
Navigator. push (
context,
MaterialPageRoute(builder: (context) => SeconPage()),
);
},


Return to the first
Now that we are on the second screen, how do we close it and return to the
first screen? Use the Navigator.pop method! pop Method to remove the
current one from the routing stack managed by Navigator Route.
In this part, update SecondScreenthe onPressedcallback in the widget


onPressed: () {
Navigator. pop (context);
},




110

Complete code
class NavigationDemo extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return FirstPage();
}

}

class FirstPage extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(title: Text( " First Page" ), backgroundColor:
Colors. pink ,),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator. push (
context,
MaterialPageRoute(builder: (context) => SeconPage()),
);
},
child: Text( "Second Page" , style: TextStyle(color:
Colors. white ),),
color: Colors. pink ,
),
),
);
}

}


class SeconPage extends StatelessWidget{
@override
111

Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(title: Text( " Second Page" ), backgroundColor:
Colors. pink ,),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator. pop (context);
},
child: Text( "Navigate to First Page" , style: TextStyle(color:
Colors. white ),),
color: Colors. pink ,
),
),
);
}

}



112

Routing table (Named Routes)
Flutter also provided Navigation with NamedRoutes

The simple way is to define all routes in the runApp, so that centralized
management is possible, which is also a very recommended approach

A MaterialApp is the easiest way to set it up, and the MaterialApp's home
becomes the route at the bottom of the navigator stack. To push a new
route on the stack, you can create a MaterialPageRoute instance with
builder capabilities


class NamedRoutes extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
113

return MaterialApp(
home: HomePage(),
routes: <String,WidgetBuilder>{
'/f' :(BuildContext ctx)=> FisrtPage(),
'/s' :(BuildContext ctx)=> SecondPage(),
'/t' :(BuildContext ctx)=> ThirdPage(),
},
);
}

}

class HomePage extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(title: Text( "HomePage" ),backgroundColor:
Colors. pink ,),
body: Center(
child: Column(
mainAxisSize: MainAxisSize. min ,
children: <Widget>[
RaisedButton(
color: Colors. pink ,
onPressed: (){
Navigator. pushNamed (context, "/f" );
},child: Text( "FirstPage" ,style: TextStyle(color:
Colors. white )),),

RaisedButton(

color: Colors. pink ,
onPressed: (){
Navigator. pushNamed (context, "/s" );
},child: Text( "SecondPage" ,style: TextStyle(color:
Colors. white )),),

114

RaisedButton(
color: Colors. pink ,
onPressed: (){
Navigator. pushNamed (context, "/t" );
},child: Text( "ThirdPage" ,style: TextStyle(color:
Colors. white ),),),
],
),
),
);
}

}

class FisrtPage extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(title: Text( "FirstPage" ),backgroundColor:
Colors. pink ,),
body: Center(
child: Column(
children: <Widget>[
RaisedButton(onPressed: (){Navigator. pop (context, "From
First page" );},child: Text( "FirstPage" ),)
],
),
),
);
}

}

class SecondPage extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
115

return Scaffold(
appBar: AppBar(title: Text( "SecondPage" ),backgroundColor:
Colors. pink ,),
body: Center(
child: Column(
children: <Widget>[
RaisedButton(onPressed: (){Navigator. pop (context);},child:
Text( "SecondPage" ),)
],
),
),
);
}

}

class ThirdPage extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(title: Text( "ThirdPage" ),backgroundColor:
Colors. pink ,),
body: Center(
child: Column(
children: <Widget>[
RaisedButton(onPressed: (){Navigator. pop (context);},child:
Text( "ThirdPage" ),)
],
),
),
);
}

}


To get the result from called page by
116

onPressed: (){
Navigator. pushNamed (context, "/f" ).then((value){
print(value);
});
}


After pop the screen the then() method will execute and print the result.


Navigation switch animation
The default navigation switch animation is a pop-up process from bottom
to top on Android, and a pan-to-left process from iOS
In order to unify, you can customize a route, including the color and
behavior of the modal barrier of the route, and the animation conversion of
other aspects of the route

You can find the example of Navigation Screen animation at
http://rrtutors.com/description/53






117

Form & Form Fields

A form is an area that contains form elements. Form elements allow users
to enter content, such as text fields, drop-down lists, radio boxes, check
boxes, and so on. Common application scenarios are: login, registration,
input information, etc. There are two important components in the form,
one is the Form component for the entire form submission, and the other is
the TextFormField component for user input

Form Constructor

const Form({
Key key,
@required this . child ,
this . autovalidate = false ,
this . onWillPop ,
this . onChanged ,
})



The Form object gives the following methods:
reset to reset fields.
save to save fields.
validate to validate, returning a true if the form fields are valid, false if
one or more are invalid

Form State
The Form object stores input state data from child TextFormFields but not
other field types like Checkboxes, DropdownButtons, Radios, Switches. So,
118

if we want form to work with those other types of fields, we need to store
the state of those items. If we
take a look a look at the example we will see that these fields are stored as
state in the Stateful Widget

Form Validation
As mentioned earlier, the Form class has an autovalidate constructor
argument.
If this argument is set to true, the framework invokes validation as data is
input.
If this argument is set to false, the framework will not invoke validation
until the validate method is invoked

Example With Login Page


class FormWidget extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _LoginPageState();
}

}
class _LoginPageState extends State<FormWidget> {

GlobalKey<FormState> loginKey = GlobalKey<FormState>();

String userName ;

String password ;

void login() {

119

var loginForm = loginKey . currentState ;

if (loginForm.validate()) {
loginForm.save();
print( 'userName : ' + userName + ' , password : ' +
password );
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text( 'Form Fileds' ),
backgroundColor: Colors. pink ,
centerTitle: true ,
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all( 16 ),
child: Form(

key: loginKey ,

autovalidate: true ,
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(
labelText: 'User Name' ,
hintText: "Enter User Name" ,
hintStyle: TextStyle(
color: Colors. grey ,
fontSize: 13 ,
),
prefixIcon: Icon(Icons. person ,color: Colors. pink ,),
120

),

validator: (value) {
return value.trim(). length > 0 ? null : "Please
enter valid user name" ;
},

onSaved: (value) {
userName = value;
},

onFieldSubmitted: (value) {},
),
TextFormField(
decoration: InputDecoration(
labelText: 'Password' ,
hintText: 'Enter password' ,
hintStyle: TextStyle(
color: Colors. grey ,
fontSize: 13 ,
),
prefixIcon: Icon(Icons. lock ,color: Colors. pink ),
),

obscureText: true ,

validator: (value) {
return value. length < 6 ? 'Password should be
min 6 characters' : null ;
},
onSaved: (value) {
password = value;
},
),

],
),

121

onChanged: () {
print( "onChanged" );
},
),
),
Container(
padding: EdgeInsets.all( 16 ),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(
padding: EdgeInsets.all( 15 ),

child: Text(
"Login" ,
style: TextStyle(fontSize: 18 ),
),
textColor: Colors. white ,
color: Colors. pink ,
onPressed: login,
),
),
],
),
)
],
),
),
);
}
}



122

Input Decoration Themes
By using this Input Decoration themes we can change the style for form
fields as we like


ThemeData(
scaffoldBackgroundColor: Color(0xFF000000),
appBarTheme: AppBarTheme(
color: Colors.white,
textTheme: TextTheme(
title: TextStyle(fontSize: 22, color: Colors.white),
)
123

),
brightness: Brightness.dark,
backgroundColor: Color(0xFF000000),
accentColor: Colors.white,
accentIconTheme: IconThemeData(color: Colors.black),
dividerColor: Colors.black54,

accentTextTheme:TextTheme(
headline: TextStyle(fontSize: 35, color: Colors.white),
title: TextStyle(fontSize: 35, color: Colors.white),
body1: TextStyle(fontSize: 35, color: Colors.white),
subtitle: TextStyle(fontSize: 18, color: Colors.white),
display1: TextStyle(fontSize: 35, color: Colors.white)
),
inputDecorationTheme: InputDecorationTheme(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.all(Radius.circular(10))),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.all(Radius.circular(10))),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.all(Radius.circular(10))),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.all(Radius.circular(10))),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.all(Radius.circular(10)),
),
labelStyle: TextStyle(
color: Colors.white,
fontSize: 12.0
),
),
buttonTheme: ButtonThemeData(
shape: new RoundedRectangleBorder(
124

borderRadius: BorderRadius.all(Radius.circular(10.0)),
side: BorderSide(color: Colors.white)),
)
);



We can change the Theme of application dynamically, you can find sample
at
http://rrtutors.com/description/27






















125

Networking & JSON and Serialization
Now a days every mobile application communicate with remote server on
Networking

Flutter provides a sky_enginedevelopment kit in the Flutter engine , which
contains a _http library that contains various operation classes related to
encapsulated http requests. In this article, we will introduce _http the use
of related operation classes and the use _httpof three-party dio network
libraries based on encapsulation

HTTP Introduction
The Hypertext Transfer Protocol (HTTP) is designed to enable
communications between clients and servers. HTTP works as a
request-response protocol between a
client and server. A protocol describes how machines communicate with
each other using messages. A protocol defines the format of these messages

HTTPClient
Make HTTPRequest
http support is located dart:io , so to create an HTTP client, we need to add
an import

import 'dart:io' ;

var httpClient = new HttpClient ();

126

HTTP API uses Dart Futures in the return value . We recommend using the
async/ await syntax to call the AP

Involve below steps to handle the HttpClient
●Create client
●Construct Uri
●Make a request, wait for a request, and you can also configure request
headers and body
●Close the request and wait for a response
●Decode the content of the response

get() async {
var httpClient = new HttpClient();
var uri = new Uri.http(
'domain' , 'path to api' , params in map object);
var request = await httpClient.getUrl(uri);
var response = await request.close();
var responseBody = await response.transform(UTF8.decoder).join();
}


Decode and encode JSON

The dart:convertlibrary makes it easy to decode and encode JSON.
Decode a simple JSON string and parse the response into a Map

Map data = JSON.decode(responseBody);
String name=mapNews[0]['name']




127

Check Example

class NetwotkHTTP extends StatefulWidget {
NetwotkHTTP({Key key}) : super (key: key);

@override
_NetwotkHTTPState createState() => new _NetwotkHTTPState();
}

class _NetwotkHTTPState extends State<NetwotkHTTP> {

Map<int, dynamic > mapNews =Map();

@override
void initState() {
// TODO: implement initState
super .initState();
_getNewsData();
}

_getNewsData() async {

var
url= 'https://newsapi.org/v2/sources?apiKey=API_KEY&p
age=1' ;
//var url = 'https://httpbin.org/ip';
var httpClient = new HttpClient();

var listNewsdata= "" ;
try {
var request = await httpClient.getUrl(Uri. parse (url));
var response = await request.close();
if (response. statusCode == HttpStatus. OK ) {
var json = await response.transform(utf8. decoder ).join();
var data = jsonDecode(json);



128

List< dynamic >hm=data[ 'sources' ] as List;

setState(() {
mapNews =hm.asMap();
print( "errorr SetState" + mapNews .toString());
});



} else {
print( "errorr " );
listNewsdata =
'Error Resposne : \n Http status ${response. statusCode } ' ;
}
} catch (exception) {
print( "errorr $exception " );
listNewsdata = 'Failed getting News Data $exception ' ;
}

// If the widget was removed from the tree while the message was
in flight,
// we want to discard the reply rather than calling setState to
update our
// non-existent appearance.
if (! mounted ) return ;


}

@override
Widget build(BuildContext context) {
var spacer = new SizedBox(height: 32.0 );

return new Scaffold(
appBar: AppBar(title: Text( "News API WITH HTTP
CLIENT" ),backgroundColor: Colors. pink ,),
body: SingleChildScrollView(

129

child: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment. center ,
children: <Widget>[
( mapNews . length == 0 )?CircularProgressIndicator():Text( "" ),

ListView.builder(
shrinkWrap: true ,
primary: false ,
itemCount: mapNews . length ,
itemBuilder: (ctx,pos){
return Card(
elevation: 5 ,
child: Container(
margin: EdgeInsets.all( 5 ),
padding: EdgeInsets.all( 5 ),
child: InkWell(
onTap: (){},
child: Row(
children: <Widget>[
Container(
height: 50 ,
width: 50 ,
decoration: ShapeDecoration(shape: CircleBorder(),color:
Colors. pink ),
child: Center(child:
Text( mapNews [pos][ 'name' ].substring( 0 , 1 ).toUpperCase(),style:
TextStyle(fontSize: 30 ,color: Colors. white ),)),
),
SizedBox(width: 15 ,),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment. start ,
children: <Widget>[
Text( mapNews [pos][ 'name' ],style: TextStyle(fontSize:
18 ,color: Colors. black ),),
SizedBox(height: 5 ,),
Text( mapNews [pos][ 'description' ],style:
130

TextStyle(fontSize: 12 ,color: Colors. grey [ 800 ]),maxLines: 3 ,),
],
),
)
],
),
),
)
);
})


],
),
),
),
);
}
}




HTTP Library
http Library http.dartfile package HttpClientclass is our common network
requests the operation class, which is an abstract class, the specific
operation by the http_impl.dart document _HttpClient class that
implements the class encapsulates http request various methods, including
get, post, put, delete, patchAnd head wait for the request

Let's look at the usage method through the following example

131

In this example using the NewsAPI to fetch the news headlines. News API
is a simple HTTP REST API for searching and retrieving live articles from
all over the web

To call api in Flutter we need to add http: ^0.12.0+2 dependencies in the
pubspec.yaml file

The above same example with http library

static Future callNewsCAtegory () async {
var url= "API_KEY" ;
return
get( 'https://newsapi.org/v2/sources?apiKey= $url &page=1' )
;
}


The above method will return the response data, that we are handle in
below code


fetchNews(){
var callNews = NewsCategoryModel. callNewsCAtegory ();
callNews.then((data){
var response=json.decode(data.body );
print(response);
var listNewsdata=response[ 'sources' ] as List;
setState(() {

listNews =listNewsdata.map<NewsCategoryModel>((model)
=>NewsCategoryModel.fromJson(model)).toList();
listNewsAll .clear();
listNewsAll .addAll( listNews );
});

132

},onError: (error){
print( "Result Error $error " );
}
);

}



POST Method
Map<String, String> queryParameters = { 'key' : 'value' , 'key' :
'value' };
Map<String, String> header = { 'key' : 'value' };
post( "API_URL" ,body: queryParameters,headers: header);


JSON Parsing

After getting the response from the API we need to parse the data, for this
we are using the import 'dart:convert' library

var callNews = NewsCategoryModel. callNewsCAtegory ();
callNews.then((data){
var response=json.decode(data.body );
print(response);
var listNewsdata=response[ 'sources' ] as List
Var
listNews =listNewsdata.map<NewsCategoryModel>((model)=>Ne
wsCategoryModel.fromJson(model)).toList();



The NewsCategoryModel class like below
133

class NewsCategoryModel {
String id ;
String name ;
String description ;
String url ;
String category ;
String language ;
String country ;


NewsCategoryModel( this . id , this . name , this . description , this . u
rl , this . category , this . language , this . country );


NewsCategoryModel.fromJson(Map<String, dynamic >parseModel
)
{
id =parseModel[ 'id' ];
name =parseModel[ 'name' ];
description =parseModel[ 'description' ];
url =parseModel[ 'url' ];
category =parseModel[ 'category' ];
language =parseModel[ 'language' ];
country =parseModel[ 'country' ];
}

static Future callNewsCAtegory () async {
var url= "API_KEY" ;
return
get( 'https://newsapi.org/v2/sources?apiKey= $url &page=1' )
;
}
}

134

CompleteExample

class NewsCategory extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return NewsCategorystate();
}

}
class NewsCategorystate extends State<NewsCategory>{
static const _appPrimaryValue = Colors. pink ;
List<NewsCategoryModel> listNews ;
List<NewsCategoryModel> listNewsAll ;
Icon _searchIcon = new Icon(Icons. search );
Widget _appBarTitle = new Text( 'Search by Category' );
TextEditingController searchController = new
TextEditingController();
List<Color> liscolors = new List();
@override
void initState() {
// TODO: implement initState
super .initState();

liscolors .add(Color( 0xFF009688 ));
liscolors .add(Color( 0xFFFF0080 ));
liscolors .add(Color( 0xFF800080 ));
listNews = new List();
listNewsAll = new List();

//_searchPressed();
searchController .addListener((){
print( searchController . text );
if ( searchController . text . isEmpty ) {

setState(() {
135

listNews .clear();
listNews .addAll( listNewsAll );

});
} else {
setState(() {
listNews .clear();
for (int k= 0 ;k< listNewsAll . length ;k++)
{
print( listNewsAll [k]. name + " names " );

if ( listNewsAll [k]. name .toLowerCase().contains( searchControl
ler . text .toLowerCase()))
{
print( listNewsAll [k]. name + " names inside" );
listNews .add( listNewsAll [k]);
}
}
});
}
});
fetchNews();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
backgroundColor: _appPrimaryValue ,
title: _appBarTitle ,
leading: IconButton(icon: this . _searchIcon , onPressed: (){
_searchPressed();
}),
),
body:( listNews . length > 0 )?ListView.builder(
itemCount: listNews . length ,
itemBuilder: (ctx,index){
return setNewsItem( listNews [index],index);
136

}):Center(child: CircularProgressIndicator(),),

);
}


setNewsItem(NewsCategoryModel newsModel,index)
{
Color color=Colors. green [ 700 ];
if (index== 0 ||index== 5 ||index== 11 )
color= liscolors [ 0 ];
else if (index% 2 == 0 )
color= liscolors [ 1 ];
else color= liscolors [ 2 ];
return Card(
elevation: 5 ,
child: Container(
margin: EdgeInsets.all( 5 ),
padding: EdgeInsets.all( 5 ),
child: InkWell(
onTap: (){
HashMap<String,String>hm= new HashMap();
hm[ 'category' ]=newsModel. category ;

Navigator. pushNamed ( context , "/news" ,arguments: hm);
},
child: Row(
children: <Widget>[
Container(
height: 50 ,
width: 50 ,
decoration: ShapeDecoration(shape: CircleBorder(),color:
color),
child: Center(child:
Text(newsModel. name .substring( 0 , 1 ).toUpperCase(),style:
TextStyle(fontSize: 30 ,color: Colors. white ),)),
),
SizedBox(width: 15 ,),
137

Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment. start ,
children: <Widget>[
Text(newsModel. name ,style: TextStyle(fontSize: 18 ,color:
Colors. black ),),
SizedBox(height: 5 ,),
Text(newsModel. description ,style: TextStyle(fontSize:
12 ,color: Colors. grey [ 800 ]),maxLines: 3 ,),
],
),
)
],),
),),
);
}


fetchNews(){
var callNews = NewsCategoryModel. callNewsCAtegory ();
callNews.then((data){
var response=json.decode(data.body );
print(response);
var listNewsdata=response[ 'sources' ] as List;
setState(() {

listNews =listNewsdata.map<NewsCategoryModel>((model)=>Ne
wsCategoryModel.fromJson(model)).toList();
listNewsAll .clear();
listNewsAll .addAll( listNews );
});


},onError: (error){
print( "Result Error $error " );
}
);

138

}
void _searchPressed() {
setState(() {
if ( this . _searchIcon . icon == Icons. search ) {
this . _searchIcon = new Icon(Icons. close );
this . _appBarTitle = new TextField(
controller: searchController ,
cursorColor: Colors. white ,
style: TextStyle(color: Colors. white ),
decoration: new InputDecoration(
hintStyle: TextStyle(color: Colors. white ),
prefixIcon: new Icon(Icons. search ,color: Colors. white ,),
hintText: 'Search...' ,
),
);
} else {
this . _searchIcon = new Icon(Icons. search );
this . _appBarTitle = new Text( 'Search Example' );

searchController .clear();
}
});
}
}




139

140

Database and local storage
In Android we have different ways to store data
●SharedPreferences
●Local database
●Files

Similarly in Flutter also we can handle the data by above ways

SharedPreferences
Shared Preferences allow us to save and retrieve data in the form of
key,value pair

How to access Shared Preferences in Flutter?
In Flutter, we can access this feature by using the plugin
Shared_Preferences

Example

class MySharedPref extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return MySharedPrefState();
}

}

class MySharedPrefState extends State<MySharedPref>{
@override
Widget build(BuildContext context) {
141

// TODO: implement build
return Scaffold(
appBar: AppBar(title:
Text( "SharedPreference" ),backgroundColor: Colors. pink ,),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors. pink ,
child: Icon(Icons. add ),
onPressed: (){
_incrementCounter();
}),
body: Center(
child: FutureBuilder(
future: _getIncrementCounter(),
builder:(BuildContext context, AsyncSnapshot snapshot) {
return Column(
mainAxisSize: MainAxisSize. min ,
children: <Widget>[
Text( "The Incremented Value is " ,style:
TextStyle(color: Colors. pink ,fontSize: 20 ),),
SizedBox(height: 20 ,),

Text((snapshot. data == null )? "" :snapshot. data .toString(),style:
TextStyle(color: Colors. pink ,fontSize: 20 ),),
],
);
},
),
),
);
}


_incrementCounter() async {
SharedPreferences prefs = await
SharedPreferences. getInstance ();
int counter = (prefs.getInt( 'counter' ) ?? 0 ) + 1 ;
setState(() {
prefs.setInt( 'counter' , counter);
142

});


}

Future<int>_getIncrementCounter() async {

SharedPreferences prefs = await
SharedPreferences. getInstance ();
int counter = (prefs.getInt( 'counter' ) ?? 0 ) + 1 ;
return counter;
}
}


143

144

Database

In Android, we can use SQLite to store structured data that is queried via
SQL.

How to access SQLite in Flutter?

In Flutter, we can use the SQFlite plugin to access this feature of SQFlite

SQFlite Features
●Supports transactions and batch operations
●Automatic version management during program opening
●Addition, deletion, change, and help program
●Perform DB operations in iOS and Android background threads

SQFlite does not perform a type check on the value, that is, a column of
type INTEGER can store TEXT, but when we parse the result of the query
and map it, it will report a type exception. So still avoid storing inconsistent
data

SQFlite supports 5 data types: NULL , INTEGER , REAL , TEXT , BLOB

NULL
When a column does not store data, the default value is NULL.

INTEGER
Int type in dart, the value range is -2 ^ 63 to 2 ^ 63-1

REAL
145

num type in dart, namely int and double types

TEXT
String type in dart
BLOB
The Uint8List type in dart, although it can store List <int>, is not officially
recommended because the conversion is slow

bool
Stores INTEGER type, 0 is false, 1 is true

If we need to store other types of data, such as bool, DateTime, List
<String>, etc., we need to handle it by ourselves. Everyone may have their
own unique method. I hope you can make some suggestions. We can
encapsulate entity classes and parsing classes. From the perspective of
external code, these types of storage, such as bool, DateTime, and List
<String>, are implemented

DateTime
Store INTEGER type, the creation time and update time of a column of data
is generally more important. Of course, there are other information, such as
the payment time, delivery time, and cancellation time of an order. If the
TEXT type is stored, the program is inconvenient if it supports multiple
languages.

List
To store TEXT type, we can combine the data into String and store it in the
database according to the special separator. It is then parsed into a List
<String> according to the split of the String. There are still many things to
note, such as the elements of List must not contain the defined delimiters.
It is troublesome to modify a certain Item of List, and it can only cover List
as a whole.

146

Map, json, entity classes
Store the TEXT type. Generally, I use the toMap method of the entity class
to convert the entity class into a Map. The entity class is converted to a
String through jsonEncode. In turn, the string is converted to a Map using
jsonDecode, and the entity class is converted from the Map to the entity
class


Database operations

Database creation
Open the database based on the name and version number

createDB(VERSION) async {
String databasesPath = await getDatabasesPath();
// Database Path: /data/user/0/com.package.name/databases
String path = join(databasesPath, 'db_name.db' );
// Path: /data/user/0/com.package.name/databases/db_name.db
Database database = await openDatabase(
path,
version: VERSION,
onCreate: (Database db, int version) async {

},
onUpgrade: (Database db, int oldVersion, int newVersion) async {

},
);
}


Create Table
The Create Table query should be inside onCreate() method

"CREATE TABLE users(id INTEGER PRIMARY KEY autoincrement, name TEXT, email TEXT,
password TEXT, mobile TEXT)" ;


147

Delete Table

db.execute( 'DROP table users' );

Clear Table
db.execute( 'DELETE FROM users' );

Rename Table
db.execute( 'ALTER TABLE users RENAME TO users_1' );

Add Field
db.execute( 'ALTER TABLE users ADD gender TEXT' );

Delete Field
db.execute( 'ALTER TABLE users DROP COLUMN gender' );

Modify Field Type
db.execute( 'ALTER TABLE users ALTER COLUMN value integer' );


Insert
Insert will returns the last inserted record id
int id = await database.rawInsert( 'INSERT INTO user(name, email, password,
mobile) VALUES("shiva", "[email protected]", "1234#","1234567899")' );

Delete
returns the number of records affected

int count = await database.rawDelete( 'DELETE FROM user WHERE email = ?' ,
[ '[email protected]' ]);


148

Update
int count = await database.update( 'user' ,
{ 'name' : 'Name 2' }
where: 'email = ?' ,
whereArgs: [ '[email protected]' ]

Query
Query is the most complicated one in SQL statements. The keywords
include distinct, where, group by, having, count, order by asc / desc, limit,
offset, in, join, as, union and so on

List<Map<String, dynamic >> result = await database.query(
'user' ,
distinct: true ,
columns: [ 'name' , 'mobile' ],
where: 'email = ?' ,
whereArgs: [ '[email protected]' ],
groupBy: 'name' ,
limit: 5 ,
offset: 2 ,
);

List<Map<String, dynamic >> result = await database.rawQuery(
'SELECT * FROM user WHERE [email protected] order by name asc limit 5
offset 2' ,
[ 16 ],
);

Example
Add Plugins
Add below plugins to pubspec.yaml file
sqflite:
path:
path_provider: ^0.4.1

Create User Model class
class User{
int id;
String name;
String email;
149

String pasword;
String mobile;
User( this .name, this .email, this .pasword, this .mobile);
Map<String,dynamic>toUserMap(){
return {
'name' :name,
'email' :email,
'password' :pasword,
'mobile' :mobile,

};
}

static fromMap(Map<String, dynamic> c) {

return User(c[ 'name' ],c[ 'email' ],c[ 'passowrd' ],c[ 'mobile' ]);
}

}

Create Database

import 'dart:io' ;

import 'package:flutter_firebase_app/models/user.dart' ;
import 'package:path/path.dart' ;
import 'package:sqflite/sqflite.dart' ;

import 'package:path_provider/path_provider.dart' ;

class UserDatabase{
static String path;
static final _databaseName = "mydb.db" ;
static final _databaseVersion = 1 ;

static final _table_user = 'users' ;
static final _table_logins = 'logins' ;

UserDatabase._privateConstructor();
static final UserDatabase instance = UserDatabase._privateConstructor();

// only have a single app-wide reference to the database
static Database _database;


Future<Database> get database async {
if (_database != null ) return _database;
// lazily instantiate the db the first time it is accessed
_database = await _initDatabase();
return _database;
}

// this opens the database (and creates it if it doesn't exist)
_initDatabase() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, _databaseName);
150

return await openDatabase(path,
version: _databaseVersion,
onCreate: _onCreate);
}

// SQL code to create the database table
Future _onCreate(Database db, int version) async {
await db.execute(
"CREATE TABLE users(id INTEGER PRIMARY KEY autoincrement, name TEXT,
email TEXT, password TEXT, mobile TEXT)" ,
);
await db.execute(
"CREATE TABLE logins(name TEXT, email TEXT, mobile TEXT,password TEXT)" ,
);
}




static Future<String> getFileData() async {
return getDatabasesPath().then((s){
return path=s;
});
}

Future<int> insertUser(User user) async {
Database db = await instance.database;

var users= await db.rawQuery( "select * from users where mobile =
" +user.mobile);
if (users.length> 0 )
{
return - 1 ;
}
return await db.insert( "users" ,user.toUserMap(),conflictAlgorithm:
ConflictAlgorithm.ignore
);
}

Future<User> checkUserLogin(String mobile, String password) async
{
Database db = await instance.database;
var res= await db.rawQuery( "select * from users where mobile = ' $mobile '
and password = ' $password '" );
if (res.length> 0 )
{
List<dynamic> list =
res.toList().map((c) => User.fromMap(c)).toList() ;

print( "Data " +list.toString());
await db.insert( "logins" ,list[ 0 ].toUserMap());
return list[ 0 ];
}
return null ;
}

Future<int> getUser() async {
Database db = await instance.database;
var logins= await db.rawQuery( "select * from logins" );
if (logins== null )
151

return 0 ;
return logins.length;

}

Future<User> getUserData() async {
Database db = await instance.database;
var res= await db.rawQuery( "select * from logins" );
print( "result user data $res " );
print( "result user data " +res.toString());
List<dynamic> list =
res.toList().map((c) => User.fromMap(c)).toList() ;
return list[ 0 ];

}

Future<int> deleteUser(String mobile) async {
Database db = await instance.database;
var logins= db.delete(_table_logins, where: "mobile = ?" , whereArgs:
[mobile]);
return logins;

}
}

Signup Page

import 'package:flutter/material.dart' ;
import 'package:flutter_firebase_app/databases/UserDatabase.dart' ;
import 'package:flutter_firebase_app/models/user.dart' ;

class SignupPage extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return SignUpState();
}

}

class SignUpState extends State<SignupPage>{
final _formKey = GlobalKey<FormState>();
final _scafoldKey = GlobalKey<ScaffoldState>();
final _nameEditController=TextEditingController();
final _emailEditController=TextEditingController();
final _mobileEditController=TextEditingController();
final _passwordEditController=TextEditingController();
String email_pattern =
r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,
3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'
;
String password_pattern = r'^[a-zA-Z0-9]{6,}$' ;
String mobile_pattern = r'^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-.
]?([0-9]{4})$' ;
Size size;

152

@override
Widget build(BuildContext context) {
size=MediaQuery.of(context).size;
return new Scaffold(
key: _scafoldKey,
body: Stack(
children:<Widget>[
Image.asset( "splash_img.png" ,fit: BoxFit.cover, width: size.width,height:
size.height,),
Container(color: const Color( 0x99FFFFFF ),),
Container(
height: 120 ,
decoration: new BoxDecoration(
border: Border.all(color: Colors.teal),
borderRadius: BorderRadius.only(bottomLeft:
Radius.circular(size.width/ 2 ),topRight: Radius.circular(size.width/ 2 )),
color: Colors.teal,

),
),

Center(
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(left: 20 ,right: 20 ),
child: Form(
key: _formKey,
child:
Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(height: 20 ,),
Container(
decoration: new BoxDecoration(
border: new Border.all(color: Colors.teal),
borderRadius: BorderRadius.circular( 10 ),
color: Colors.teal,

),

child: Padding(
padding: const EdgeInsets.all( 8.0 ),
child: Text( "Registration Form" ,style: TextStyle(color:
Colors.white,
fontSize: 22
),),
),
),
SizedBox(height: 40 ,),
//--------------Name
FormFiled------------------------------------------
TextFormField(
controller: _nameEditController,
textInputAction: TextInputAction.next,

validator: (value){
if (value.isEmpty)
{
return "Enter Name" ;
153

}
return null ;
},
style: getTextStyle(),
decoration: customInputDecoration( "Enter Name" ),
),
SizedBox(height: 20 ,),
//--------------Email
FormFiled------------------------------------------
TextFormField(
controller: _emailEditController,
textInputAction: TextInputAction.next,
validator: (value){
RegExp regex =RegExp(email_pattern);
if (!regex.hasMatch(value))
return 'Enter Valid Email' ;
else
return null ;
},
keyboardType: TextInputType.emailAddress,
style: getTextStyle(),
decoration: customInputDecoration( "Enter email id" ),
),
SizedBox(height: 20 ,),

//--------------Mobile
FormFiled------------------------------------------
TextFormField(
controller: _mobileEditController,
textInputAction: TextInputAction.next,
validator: (value){
RegExp regex =RegExp(mobile_pattern);
if (!regex.hasMatch(value))
return 'Enter valid mobile number' ;
else
return null ;
return null ;
},
keyboardType: TextInputType.number,
maxLength: 10 ,
style: getTextStyle(),
decoration: customInputDecoration( "Enter mobile number" ),
),
SizedBox(height: 20 ,),
//--------------Password
FormFiled------------------------------------------
TextFormField(
controller: _passwordEditController,
textInputAction: TextInputAction.done,
validator: (value){
RegExp regex =RegExp(password_pattern);
if (!regex.hasMatch(value))
return 'Password should be in alphanumaric with 6
characters' ;
else
return null ;
},
obscureText: true ,
style: getTextStyle(),
decoration: customInputDecoration( "Enter password" ),
154

),

SizedBox(height: 20 ,),
RaisedButton(onPressed: (){

if (_formKey.currentState.validate())
{

UserDatabase.instance.insertUser(User(_nameEditController.text,_emailEditContr
oller.text,_passwordEditController.text,_mobileEditController.text)).then((res
ult){
if (result==- 1 )
{
_scafoldKey.currentState
.showSnackBar(SnackBar(content: Text( 'User
with same number already existed $result ' )));
} else
{
_scafoldKey.currentState
.showSnackBar(SnackBar(content: Text( 'User
Registered Succesfully $result ' )));
Navigator.pushReplacementNamed(context,
"/login" );
}

}) ;

}

}, shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular( 18 ),
),
color: Colors.pink,
child: Text( "Signup" , style: TextStyle(color:
Colors.white,fontSize: 20 ),),
),

FlatButton(
child: Text( "Already have account, Sign In?" ),
onPressed: (){

Navigator.pushReplacementNamed(context, "/login" );
},
)
],
)
),
),
),
)
],
),
);;
}


TextStyle getTextStyle(){
return TextStyle(
fontSize: 18 ,
color: Colors.pink
155

);
}

InputDecoration customInputDecoration(String hint)
{

return InputDecoration(
hintText: hint,
hintStyle: TextStyle(
color: Colors.teal
),
contentPadding: EdgeInsets.all( 10 ),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular( 12 ),
borderSide: BorderSide(
color: Colors.pink
)
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular( 8 ),
borderSide: BorderSide(
color: Colors.pink
)
),

);
}

}



Login Page
import 'package:flutter/material.dart' ;
import 'package:flutter_firebase_app/databases/UserDatabase.dart' ;

class LoginPage extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return LoginState();
}

}
class LoginState extends State<LoginPage>
{
final _formKey = GlobalKey<FormState>();
final _scaffoldKey = GlobalKey<ScaffoldState>();
final _mobileController=TextEditingController();
final _passwordController=TextEditingController();
final FocusNode _mobileFocus = FocusNode();
final FocusNode _passwordFocus = FocusNode();
Size size;
@override
Widget build(BuildContext context) {
size = MediaQuery.of(context).size;
156

return new Scaffold(
key: _scaffoldKey,
body: Stack(
children:<Widget>[
Image.asset( "splash_img.png" ,fit: BoxFit.cover,
width: size.width,
height: size.height,
),
Padding(
padding: EdgeInsets.only(left: 20 ,right: 20 ),
child: Form(
key: _formKey,
child:
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(height: 20 ,),

TextFormField(
controller: _mobileController,
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,

focusNode: _mobileFocus,
onFieldSubmitted: (term){
FocusScope.of(context).requestFocus(_passwordFocus);
},
validator: (value){
if (value.isEmpty)
{
return "Enter mobile number" ;
}
return null ;
},
style: getTextStyle(),
decoration: customInputDecoration( "Enter mobile number" ),
),
SizedBox(height: 20 ,),
TextFormField(
textInputAction: TextInputAction.done,
controller: _passwordController,
keyboardType: TextInputType.text,

obscureText: true ,
focusNode: _passwordFocus,
validator: (value){
if (value.isEmpty)
{
return "Enter Password" ;
}
return null ;
},
style: getTextStyle(),
decoration: customInputDecoration( "Enter password" ),
),
SizedBox(height: 20 ,),
RaisedButton(onPressed: (){

if (_formKey.currentState.validate())
{
157

UserDatabase.instance.checkUserLogin(_mobileController.text,_passwordControlle
r.text).then((result){

if (result== null )
{

_scaffoldKey.currentState.showSnackBar(SnackBar(content: Text( "Please enter
valid details" )));
}
else
{
Navigator.pushReplacementNamed(context, "/home" );
}
});
}

}, shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular( 18 ),
),
color: Colors.pink,
child: Text( "Login" , style: TextStyle(color:
Colors.white,fontSize: 20 ),),
),

FlatButton(
child: Text( "Don't have account, Signup?" ),
onPressed: (){
Navigator.pushReplacementNamed(context, "/signup" );
},
)
],
)
),
)
] ,
),
);
}
TextStyle getTextStyle(){
return TextStyle(
fontSize: 18 ,
color: Colors.pink
);
}

InputDecoration customInputDecoration(String hint)
{
return InputDecoration(
hintText: hint,
hintStyle: TextStyle(
color: Colors.teal
),
contentPadding: EdgeInsets.all( 10 ),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular( 12 ),
borderSide: BorderSide(
color: Colors.pink
)
158

),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular( 8 ),
borderSide: BorderSide(
color: Colors.pink
)
),

);
}
}
Home Page

import 'package:flutter/material.dart' ;
import 'package:flutter_firebase_app/databases/UserDatabase.dart' ;
import 'package:flutter_firebase_app/models/user.dart' ;

class Homepage extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState

return HomeState();
}

}

class HomeState extends State<Homepage>{
Size size ;
User user ;
@override
void initState() {
// TODO: implement initState
super .initState();
UserDatabase. instance .getUserData().then((result){
setState(() {
user =result;
});

});
}
@override
Widget build(BuildContext context) {
size =MediaQuery. of (context). size ;
return Scaffold(
appBar: AppBar(
title: Text( "Home" ),
),
body: Column(
mainAxisSize: MainAxisSize. max ,
children: <Widget>[

Row(

mainAxisAlignment: MainAxisAlignment. end ,

children: <Widget>[
159

Padding(
padding: const EdgeInsets.all( 12.0 ),
child: RaisedButton(
onPressed: (){


UserDatabase. instance .deleteUser( user . mobile ).then((res){
if (res== 1 )
{
Navigator. pushReplacementNamed (context, "/login" );
}

});
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular( 15 ),

),
color:Colors. pink ,
child: Text( "Logout" , style: TextStyle(color:
Colors. white
),)
),
)
],
),
Container(

height: size . height - 200 ,
child: Center(
child: ( user == null )? null :Text( "Welcome User " + user . name ),
),
),
],
)
);
}

}


Check sample at http://rrtutors.com/description/8



160

State Management
We are always looking for a powerful way of state management. We knows
flutter itself has provided us with state management Stateful widget

Flutter has different ways of estate management topics
Stateful Widget
InheritedWidget
Provider
BLoC

Stateful Widget
Widgets which will change its behaviour/state dynamically called stateful
widgets
Stateful widgets are useful when the part of the user interface you are
describing can change dynamically. User interfaces need to respond to a
variety of things: The user doing something in the user interface.
Receiving data from another computer.

This is what Stateful Widgets are for. They store data (state) in an
associated State class and they can respond when that data (state) changes
as the result of the user doing something

Let's create a Counter app with Stateful widget

class MyStatefulwidget extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return MyState();
161

}

}

class MyState extends State<MyStatefulwidget>{
int count ;
@override
void initState() {
// TODO: implement initState
super .initState();
count = 0 ;
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(title: Text( "Statefulwidget" ),backgroundColor:
Colors. pink ,),
floatingActionButton: FloatingActionButton(onPressed: (){
setState(() {
count ++;
});
},child: Icon(Icons. add ,color: Colors. white ,),backgroundColor:
Colors. pink ,),
body: Container(
child: Center(
child: Text( "Count : $ count " ,style: TextStyle(color:
Colors. pink ,fontSize: 20 ),),
),
),
);
}

}


here on tap on add button every time we are updating the state by calling
the setState() method, so this will entirely rebuild the widget
This will be useful when a single widget needs to update the State.


InheritedWidget
Flutter provides an InheritedWidget that can define provide context to
every widget below it in the tree.
InheritedWidget is a special widget that can store and retrieve data , and
subcomponents can obtain stored data. Commonly used MediaQuery and
Theme are inherited from InheritedWidget
162

While this is nice in theory, we can see that it takes quite a lot of code to get
a basic example wired up. Fortunately, there are libraries like Bloc, Redux,
and Scoped Model abstract this complexity away
Let's check the counter app with InheritedWidget

Create InheritedWidget
class CounterInherited extends InheritedWidget{

final Map _counter ={ 'count' : 0 };

Widget child ;
CounterInherited ({ @required Widget this . child }): super (child:child);


get counter => _counter [ 'count' ];

increment() {
_counter [ 'count' ]++;
}

@override
bool updateShouldNotify(InheritedWidget oldWidget) {
// TODO: implement updateShouldNotify
return true ;
}

static CounterInherited of (BuildContext ctx)=>
ctx.inheritFromWidgetOfExactType(CounterInherited);

}

Here we are extending the class with InheritedWidget, which have override
method will tell the widget to need to update state or not

@override
bool updateShouldNotify(InheritedWidget oldWidget) {
// TODO: implement updateShouldNotify
return true ;
}


Create Child widget
Child widget will have the counter increment UI

163

class Counter extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return CounterState();
}

}

class CounterState extends State<Counter>{
@override
Widget build(BuildContext context) {
int count=CounterInherited. of (context). counter ;

return Scaffold(
appBar: AppBar(title: Text( "InheritedWidget" ),centerTitle:
true ,backgroundColor: Colors. pink ,),
floatingActionButton: FloatingActionButton(onPressed: (){
setState((){});
CounterInherited. of (context).increment();
},child: Icon(Icons. add ,color: Colors. white ,),backgroundColor:
Colors. pink ,),
body: Container(
child: Center(
child: Text( "Count : $count " ,style: TextStyle(color:
Colors. pink ,fontSize: 20 ),),
),
),
);
}

}

This Child widget need parent widget instance to update counter value,
This will done by static method of CounterInherited widget

CounterInherited.of(context)

Main Widget
Now create a widget which contains parent widget as Inherited widget and
pass child widget of our counter widget

class MyInherited extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return CounterInherited(
child: Counter(),
);
}
164

}
void main() => runApp(MyInherited ());
BLoC
Flutter, however, brings a new reactive style that is not entirely compatible
with MVC. Its design idea is to separate data from views, and render views
by data mapping

A variation of this classical pattern has emerged from the Flutter
community – BLoC



What is BLoC?
BLoC stands for Business Logic Components, BLoC is a method of building
applications using reactive programming. This is a completely
asynchronous world composed of streams

●Wrap stateful components with StreamBuilder, streambuilder will listen for a
stream
●This stream comes from BLoC
●The data in the stateful widget comes from the listening stream.
●User interaction gestures are detected and events are generated. For example,
press the button.
●Call the function of bloc to handle this event
●After processing in bloc, the latest data will be added to the sink of the stream.
●StreamBuilder listens to new data, generates a new snapshot, and calls the build
method again
●Widget is rebuilt

165

Example
Here we coding a simple counter application with BLoC

This Example show the Number counts in the first page, in the second page
we are increase the counter number, this will reflect in the fistpage
For this we are going to create app with below steps

Create bloc model
CountBLoC
class CountBLoC{


int _count = 0 ;
var _countController = StreamController<int>.broadcast();

Stream<int> get stream => _countController . stream ;
int get value => _count ;

addCount() {
_countController . sink .add(++ _count );
}

dispose() {
_countController .close();
}
}

Create Provider

class BlocProvider extends InheritedWidget{

CountBLoC bLoC = CountBLoC();

BlocProvider({Key key, Widget child}) : super (key: key, child: child);

@override
bool updateShouldNotify(InheritedWidget oldWidget) {
// TODO: implement updateShouldNotify
return true ;
}


static CountBLoC of (BuildContext context) =>
(context.inheritFromWidgetOfExactType(BlocProvider) as
BlocProvider). bLoC ;
}
166

Create First Page
This Page will show the number counts, for this we are accessing the data
with streambuilder

class CountPage extends StatelessWidget{
@override
Widget build(BuildContext context) {
final bloc = BlocProvider. of (context);
return Scaffold(
backgroundColor: Colors. white ,
appBar: AppBar(
title: Text( 'Counter Page' ,),
backgroundColor: Colors. pink ,
),
body: Center(
child: StreamBuilder<int>(
stream: bloc. stream ,
initialData: bloc. value ,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
return Text(
'Number Counts : ${snapshot. data } ' ,style: TextStyle(color:
Colors. pink ,fontSize: 20 ),
);
}),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors. pink ,
child: Icon(Icons. add ,color: Colors. white ,),
onPressed: () =>
Navigator. of (context).push(MaterialPageRoute(builder: (context)
=> DisplayPage()))),
);
}
}


Create Second page
This Page will increase the count by tap on button. With calling the
addCount function will increase the count value

class DisplayPage extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
final bloc = BlocProvider. of (context);
print( 'build' );
return Scaffold(
backgroundColor: Colors. white ,
appBar: AppBar(
167

title: Text( 'Update Count' ),
backgroundColor: Colors. pink ,
),
body: Center(
child: StreamBuilder(
stream: bloc. stream ,
initialData: bloc. value ,
builder: (context, snapshot) => Center(
child: Text( " Counter : ${snapshot. data } \n Increate Count by
Button tap" , style: TextStyle(color: Colors. pink ,fontSize: 20 ),textAlign:
TextAlign. center ,),
)),
),
floatingActionButton: FloatingActionButton(
onPressed: () => bloc.addCount(),
backgroundColor: Colors. pink ,
child: Icon(Icons. add ,color: Colors. white ,),
),
);
}

}




Now It’s time to check out Main Page
Here we are using the Provider to load the child widgets to Inherited
widget.

class MyBloc extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
child: MaterialApp(
title: 'BLoC' ,
theme: ThemeData.dark(),
home: CountPage(),
),
);
}
}





168

Firebase Integration
Firebase is a mobile and web application development platform developed
by Firebase.
Firebase supports frameworks like Flutter on a best-effort basis.
Now we are going to learn how to setup firebase for Flutter Application

Firebase Setup
Step 1: Create a new Project in on firebase console
( https://console.firebase.google.com/ )
This will ask to login with gmail.
Login with your account.
Now create new project in Firebase console


After creating project it will navigates to Console dashboard

169

Now select Android, now it will display below screen


170

Add your application package name and register application



Download google-service.json file and this under android->app folder


171

Modify your build.gradle files to use the plugin project level build.gradle file

buildscript {
repositories {
// Check that you have the following line (if not, add it):
google() // Google's Maven repository
}
dependencies {
// ...
// Add the following line:
classpath ' com.google.gms:google-services:4.3.3 ' // Google Services plugin
}
}
allprojects {
// ...
repositories {
// Check that you have the following line (if not, add it):
google() // Google's Maven repository
// ...
}
}


app level build.gradle file

apply plugin: ' com.google.gms.google-services '

That's it for Android setup

iOS Setup
Copy & Paste your Downloaded GoogleService-Info.plist into projectname/ios/Runner folder
Open projectname/ios/PODFile (Execute pod install if file not found) & Add ;

pod 'Firebase/Core;

and execute pod install

172

Open projectname/ios/Runner.xcworkspace & Choose Project & Add File to Runner & Choose
GoogleService-Info.plist with choose target of Runner


173

That's it now our application is ready for use Firebase


Firebase authentication & Google sign in using Flutter

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 and Twitter, and more

Now we are going to learn how to set up and implementing Google Signin
using Firebase authentication

Step 1: Create Flutter application
Step 2: Add dependencies
Add required dependencies in pubspec.yaml file

174

dependencies:
firebase_auth: ^0.15.4
google_sign_in: ^4.1.4


and run flutter packages get in terminal

Step 3: import required packages in to the main file

import ' package:firebase_auth/firebase_auth.dart ';
import ' package:google_sign_in/google_sign_in.dart ';

Step 4: Design Login Screen


import 'package:flutter/material.dart' ;

class LoginPage extends StatefulWidget {
@override
_LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.white,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxis Alignment.center,
chi ldren: <Widget>[
Flutt erLogo(s ize: 150 ),
SizedBox(height: 50 ),
_sign InButton(),
],
),
),
),
);
}

Widget _signInButton() {
ret urn Outli neButton (
175

s p lashCo lor: Colors.grey,
onPressed: () {},
shape: RoundedRectangleBorder(borderRad ius: Bord erRadius .circular ( 40)),
highlightElevation: 0,
border Side: BorderSide(color: Colors.grey),
child: Padding(
p adding: c onst Edg eInsets.f r omLTRB ( 0 , 10 , 0 , 10 ),
child : Row(
mai nAxisSize: M ainAxisSi ze.min ,
mainAxisAlignment: MainAxisAlignment.center,
childr en: <Widg et>[
I mage(i mage: AssetImage( "assets/goog le_logo.jpg") , height: 35.0 ),
Padding(
padding: const Edge Insets.on ly(left: 10 ),
child: Text(
'Sign in wit h Goo gle',
style: TextStyle(
fontSize: 20 ,
color: Colors.pink,
),
),
)
],
),
),
);
}
}


Step 5: Authentication
Now, we will need to create an instance of FirebaseAuth & GoogleSignIn

final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn googleSi gnIn = Go ogleSign In();

Fu t ure<St ring> signInWithGoogle() async {
fi nal Googl eSignInAccount googleSignInAccount = await googleSignIn.si gnIn();
final GoogleSignInAuthentication googleSi gnInAu thent ication =
await googleSignInAccount.authentication;

fin al AuthCr edential credenti a l = Go ogleAuthProvider.getCredentia l(
ac cessTo ken: googleSignIn Authentic ation. acces sToken,
idToken: googleSignInAuthentication.idToken,
);

fin al AuthRe sult aut hResult = await _auth.signInWithCredential(cr edential);
final Firebase User user = a uthResult.user;

as sert(!user.is Anonymous) ;
asser t ( await user.g etIdToken() ! = null );

final FirebaseUse r currentUser = await _auth.currentUser();
assert (user.uid == currentUser.uid);

176

return 'signInWithG oogle su cceeded: $use r ';
}

void signOutGoogle() async {
await googl eSignIn.signOut();

print( "User Sign Out" );
}


Now update login button onPressed functionality

onPressed: () {

signInWithGoogle().whenComplete(() {
Navigator. of (context).push(
MaterialPageRoute(
builder: (context) {
return MyHomePage();
},
),
);
});
}


Step 6: Check User Sign In
We can check already user Signin or not by below code

void isSignedIn() async {

isLoggedIn = await googleSignIn.isSignedIn();
if (isLoggedIn) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MyHomePage()),
);
}

}






177

Complete code

import 'package:firebase_auth/firebase_auth.dart' ;
import 'package:flutter/material.dart' ;
import 'package:google_sign_in/google_sign_in.dart' ;
import 'package:shared_preferences/shared_preferences.dart' ;

import 'homepage.dart' ;

class LoginPage extends StatefulWidget {
@override
_LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
final FirebaseAuth _auth = FirebaseAuth.instance;
178

final GoogleSignIn googleSignIn = GoogleSignIn();
bool isLoggedIn = false ;

@override
void initState() {
// TODO: implement initState
super .initState();
isSignedIn();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors. white ,
child: Center(
child: Column(
mainAxisSize: MainAxisSize. max ,
mainAxisAlignment: MainAxisAlignment. center ,
children: <Widget>[
FlutterLogo(size: 150 ),
SizedBox(height: 50 ),
_signInButton(),
],
),
),
),
);
}

Widget _signInButton() {
return OutlineButton(
splashColor: Colors. grey ,
onPressed: () {

signInWithGoogle().whenComplete(() {
Navigator. of ( context ).pushReplacement(
MaterialPageRoute(
builder: (context) {
return MyHomePage();
},
),
);
});
},
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular( 40 )),
highlightElevation: 0 ,
borderSide: BorderSide(color: Colors. grey ),
child: Padding(
padding: const EdgeInsets.fromLTRB( 0 , 10 , 0 , 10 ),
child: Row(
mainAxisSize: MainAxisSize. min ,
mainAxisAlignment: MainAxisAlignment. center ,
children: <Widget>[
Image(image: AssetImage( "assets/google_logo.jpg" ), height: 35.0 ,width:
40 ,),
Padding(
padding: const EdgeInsets.only(left: 10 ),
child: Text(
'Sign in with Google' ,
style: TextStyle(
179

fontSize: 20 ,
color: Colors. pink ,
),
),
)
],
),
),
);
}


Future<String> signInWithGoogle() async {
final GoogleSignInAccount googleSignInAccount = await googleSignIn .signIn();
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;

final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);

final AuthResult authResult = await _auth .signInWithCredential(credential);
final FirebaseUser user = authResult.user;

assert (!user.isAnonymous);
assert ( await user.getIdToken() != null );

final FirebaseUser currentUser = await _auth .currentUser();
assert (user.uid == currentUser.uid);

return 'signInWithGoogle succeeded: $user ' ;
}

void signOutGoogle() async {
await googleSignIn .signOut();

print( "User Sign Out" );
}


void isSignedIn() async {

isLoggedIn = await googleSignIn .isSignedIn();
if ( isLoggedIn ) {
Navigator. pushReplacement (
context ,
MaterialPageRoute(builder: (context) => MyHomePage()),
);
}


}
}



180

Chat Application with Firebase database Flutter

Now we are going to learn how to create Chat app with Firebase Database

Step 1: Create flutter application
Step 2: Create Users list page
Homepage.dart
In this Page we are fetching all the users data from Firebase database and
display

import 'dart:async' ;

import 'package:firebase_auth/firebase_auth.dart' ;
import 'package:firebase_database/firebase_database.dart' ;
import 'package:flutter/material.dart' ;
import 'package:flutter_firbase/user.dart' ;
import 'package:shared_preferences/shared_preferences.dart' ;

import 'chatpage.dart' ;

class MyHomePage extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return MyHomePageState();
}

}

class MyHomePageState extends State<MyHomePage>
{
FirebaseDatabase fireDB =FirebaseDatabase.instance;
TextEditingController _txtCtrl = TextEditingController();
FirebaseUser currentUser ;
String id ;
String nickname = "" ;
String photoUrl ;
List<User> listUsers = new List();
@override
void initState() {
// TODO: implement initState
super .initState();
getUserInfo();
}


getUserInfo() async {
181

SharedPreferences prefs = await SharedPreferences.getInstance();

setState(() {
id =prefs.getString( "id" );
nickname =prefs.getString( "nickname" );
photoUrl =prefs.getString( "photoUrl" );
});
FirebaseDatabase.instance.reference().child( 'users/-M1ZPGcD23x7uAUew5fF' )
.orderByChild( "created_at" )
.onValue
.listen((event) {
print( "data user" );
Map< dynamic , dynamic >hm=event.snapshot.value;
if (hm!= null )
{
hm.forEach((key, value) {
print(hm[key]);
});
}

});
print( "Fetching datad 0 " );
StreamSubscription<Event> subscription = fireDB
.reference()
.child( "users" )
.onValue
.listen((Event event) {
print( "Fetching datad 1 " );
print( event.snapshot.value);
Map< dynamic , dynamic >hm=event.snapshot.value;
hm.forEach((key, value) {
Map< dynamic , dynamic >users=value;
setState(() {
if (users[ 'id' ]!= id )
listUsers .add( new User(users[ 'name' ],users[ 'id' ],users[ 'photoUrl' ]));
});


});
},onError: (errror){

print( "Error ${errror.toString()} " );
});
}

@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(title: Text( "Chat $ nickname " ),),
body: Column(
mainAxisAlignment: MainAxisAlignment. start ,
children: <Widget>[

Expanded(
child:( listUsers . length > 0 )?
ListView.separated(
separatorBuilder: (context, index) {
return Divider(
color: Colors. black ,
182

);
},
itemCount: listUsers . length ,
itemBuilder: (context,index){
return ListTile(
title: Text( listUsers [index].name),
leading: Material(child:
Image.network( listUsers [index].img,),borderRadius: BorderRadius.all(
Radius.circular( 32.0 ),
),
clipBehavior: Clip. hardEdge ,),
onTap: (){
Navigator. push (context, MaterialPageRoute(builder:
(context){
return ChatPage(myid: id ,uid: listUsers [index].id ,myImg:
photoUrl ,uImg: listUsers [index].img,myName: nickname ,uName: listUsers [index].name ,);
}));
},
);
}):Center(child: CircularProgressIndicator(),)
),
Container(
margin: EdgeInsets.all( 8 ),
)
]),
);
}

String peerId = "1" ;
String peerAvatar ;


var listMessage ;
String groupChatId = "1" ;
SharedPreferences prefs ;
}


Step 3: Create Chat page
chatpage.dart
In this page we are sending the Messages to selected user and display list of messages
between two users

import 'dart:async' ;
import 'dart:convert' ;

import 'package:firebase_database/firebase_database.dart' ;
import 'package:flutter/material.dart' ;
import 'package:intl/intl.dart' ;

import 'message.dart' ;

class ChatPage extends StatefulWidget{
183

const ChatPage({ @required this . myid , @required this . uid , @required
this . myName , @required this . uName , @required this . myImg , @required this . uImg });
final String myid ;
final String uid ;
final String myName ;
final String uName ;
final String myImg ;
final String uImg ;
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return ChatPageState( myid , uid , myName , uName , myImg , uImg );
}
}

class ChatPageState extends State{
final String myid ;
final String uid ;
final String myName ;
final String uName ;
final String myImg ;
final String uImg ;
TextEditingController _txtCtrl = new TextEditingController();
FirebaseDatabase fireDB =FirebaseDatabase.instance;

ChatPageState( this . myid , this . uid , this . myName , this . uName , this . myImg , this . uImg );
List<Messages> list ;

@override
void initState() {
// TODO: implement initState
super .initState();
list = new List();
fetchMessages();
/*FirebaseDatabase().reference()
.child("messages")
.child(myid+"_"+uid)
.limitToLast(1)
.orderByChild("created_at")
.onChildAdded
.listen((event) {
Map<dynamic,dynamic>hm=event.snapshot.value;
print("Event ${hm.length}");
int k=0;

hm.forEach((key, value) {

print("Fetching Msgs ");
print(key);
if(k==hm.length)
{
setState(() {
Map map=hm[key];
list.add(Messages.fromMap(value,key));
});
}
k++;


});
184

});*/
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
leading: Material(child: Image.network( uImg ,width: 10 ,height:
10 ,),borderRadius: BorderRadius.all(
Radius.circular( 32.0 ),
),
clipBehavior: Clip. hardEdge ,),
title: Text( uName ),
backgroundColor: Colors. pink ,
),
body: Container(
child: Column(
children: <Widget>[
Expanded(
child: ( list . length > 0 )?ListView.separated(
separatorBuilder: (
context, index) => Divider(color: Colors. grey ,),
itemCount: list . length ,
reverse: false ,
itemBuilder: (context, index) {
return buildItem(index, list [index]);
}
,):Center(child: CircularProgressIndicator(),
),
),
Container(
margin: EdgeInsets.all( 8 ),
child: Row(children: <Widget>[
Expanded(child: TextField(

controller: _txtCtrl ,decoration: InputDecoration(
hintText: "Write your Message" ,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular( 8 ),
borderSide: BorderSide(color: Colors. pink )
)),)),
SizedBox(
width: 80 ,
child: FloatingActionButton(
onPressed: () => sendMessage(),
child: Icon(Icons. send ), ))
]))
],
),
),
);
}
sendMessage() {

fireDB
.reference()
.child( "messages" )
.child( getUniqueId ( myid , uid ))
.child(DateTime.now().toUtc(). millisecondsSinceEpoch .toString())
.push().set({
185

"from_id" : myid ,
"to_id" : uid ,
"from_name" : myName ,
"to_name" : uName ,
"msg" : _txtCtrl . text
}).then((value) => {
_txtCtrl . text = ''
});

}



fetchMessages()
{

fireDB
.reference()
.child( "messages" )
.child( getUniqueId ( myid , uid ))

.onValue
.listen((Event event) {
print( "Fetching datad" );
print( event.snapshot.value);
Map< dynamic , dynamic >hm=event.snapshot.value;
if (hm!= null )
{
list .clear();
hm.forEach((key, value) {

print( "Fetching Msgs $value " );
print(key);
Map m=value;
m.forEach((key, value) {
setState(() {

list .add(Messages.fromMap(value,key));
});
});



});
}

});
//StreamSubscription<Event> subscription =
}



Widget buildItem(int index, Messages msg) {
if (msg.from_id == myid ) {
// Right (my message)
return Column(
children: [
Container(
child: Column(
mainAxisSize: MainAxisSize. min ,
186

crossAxisAlignment: CrossAxisAlignment. end ,
children: <Widget>[
Text(
msg.msg,
style: TextStyle(color: Colors. black ),
),
/*SizedBox(height: 10,),
(msg.created_at!=null)?
Text(
"${readTimestamp(msg.created_at )}",
style: TextStyle(color: Colors.black,fontSize: 8),
):Text("")*/
],
),
padding: EdgeInsets.fromLTRB( 15.0 , 10.0 , 15.0 , 10.0 ),
width: 200.0 ,
decoration: ShapeDecoration(shape: OutlineInputBorder(borderRadius:
BorderRadius.circular( 8 ),borderSide: BorderSide(color: Colors. pink ))),
margin: EdgeInsets.only(bottom: 10.0 , right: 10.0 ),
)
],
mainAxisAlignment: MainAxisAlignment. end ,
crossAxisAlignment: CrossAxisAlignment. end ,
);
} else {
// Left (peer message)
return Container(
child: Column(
children: <Widget>[
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment. start ,
mainAxisSize: MainAxisSize. min ,
children: <Widget>[
Text(
msg.msg,
style: TextStyle(color: Colors. black ),
),
/*SizedBox(height: 10,),
(msg.created_at!=null)?
Text(
("${readTimestamp(msg.created_at )}"),
style: TextStyle(color: Colors.black,fontSize: 8),
):Text("")*/
],
),
padding: EdgeInsets.fromLTRB( 15.0 , 10.0 , 15.0 , 10.0 ),
width: 200.0 ,
decoration: ShapeDecoration(shape: OutlineInputBorder(borderRadius:
BorderRadius.circular( 8 ))),
margin: EdgeInsets.only(left: 10.0 ),
)
],
crossAxisAlignment: CrossAxisAlignment. start ,
),
margin: EdgeInsets.only(bottom: 10.0 ),
);
}
}

187

static String getUniqueId (String i1,String i2){
if (i1.compareTo(i2)<=- 1 ){
return i1+i2;
}
else {
return i2+i1;
}
}

String readTimestamp(DateTime timestamp) {
var now = DateTime.now();

return now.difference(timestamp). inHours .toString();
/* var format = DateFormat('HH:mm a');
var date = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
var diff = now.difference(date);
var time = '';

if (diff.inSeconds <= 0 || diff.inSeconds > 0 && diff.inMinutes == 0 ||
diff.inMinutes > 0 && diff.inHours == 0 || diff.inHours > 0 && diff.inDays == 0) {
time = format.format(date);
} else if (diff.inDays > 0 && diff.inDays < 7) {
if (diff.inDays == 1) {
time = diff.inDays.toString() + ' DAY AGO';
} else {
time = diff.inDays.toString() + ' DAYS AGO';
}
} else {
if (diff.inDays == 7) {
time = (diff.inDays / 7).floor().toString() + ' WEEK AGO';
} else {

time = (diff.inDays / 7).floor().toString() + ' WEEKS AGO';
}
}

return time;*/
}
}



Step 5: Run application
188

189