Flutter Development Course Overview
Flutter Development Course Overview
2023-2024
PLAN
Introduction to Flutter
Introduction to widgets
Examples of widgets
The roads
4
What is Dart?
5
Technologies
Native applications
Android iOS
Java Objective-C
Kotlin (2017) ▸ Swift (2014)
Advantages Disadvantages
Performances 1 application per platform
Specific interface for Costs and development time
each platform
7
Applications hybrides
Advantages Disadvantages
Shared code Performances
Reuse
Security
8
Cross-platform applications
• Examples of frameworks: React Native, Xamarin, Flutter
• Objective: to generate 1 Android and iOS application from the same code
Advantages Disadvantages
• Shared code / reuse • May require writing code
• Performances specific
9
A few
numbers
Google Trends
[Link]
11
Stack Overflow Trends
Source:[Link]
12
Installation of the environment
[Link]
13
Thebasicsof
Dart
Naming conventions
15
Types in Dart
• Everything that is placed in a variable is an object, including 'int' and 'double' types.
{"bool":"bool","null":"null"}
int a = 5;
dynamica =5;
a = "toto";
16
Lists and maps
• List: • Map:
No type 'Array' in Dart
17
Map<String, int> map1 = Map();
Map<String, int> map2 = {'var1':1,'var2':2};
print(map2['var1']); // Displays 1
Map<String,dynamic> map3 = Map();
map3['toto'] ='titi';
map3['tata'] =3;
else {
Adults
}
19
The loops
List<String> students = ['s1','s2','s3'];
for(var student in students) {
print(student);
}
// foreach((String)→void f)→void
[Link]((student) {
print(student);
});
[Link]().forEach((index, student)
{
$index:$student
});
20
Functions
int sum(int a, int b) {
return a + b;
}
21
The classes
class Person {
Stringname;
Person([Link]);
}
Person(String name) {
[Link] = name;
}
Personp=Person("toto");
22
Introduction
tothewidgets
What is a widget?
24
Stateless widgets
• No state
• Contains only one method: "Widget
build(BuildContext context)
• Cannot be 're-builder' by itself
• Life cycle:
• Initialization
• Rendering (build() method)
25
Stateless widgets
26
Stateful widgets
• Contains a state
• The 'build()' method is relocated to the state.
• A single method: "State<T> createState()" where
<T> corresponds to the StatefulWidget class
• The 'build' method is called each time
modification of the state
• State = set of attributes of the State class
• "initState()" : méthode pour initialisation le state
27
Stateful Widgets
• Behaves a state
• The 'build()' method is moved to the state.
• A single method: "State<T> createState()" where
T corresponds to the StatefulWidget class
• Method "build" called on each modification of the
state
• State = set of attributes of the class State
• "initState()" : méthode pour initialisation le state
28
Stateful widgets
class MyApp extends StatefulWidget {
@override
_MyAppState createState() =>
MyAppState();
}
@override
voidinitState() {
_counter=0;
[Link]();
}
@override
Widget build(BuildContext context) {
returnText("Compteur$_counter");
}
}
29
The Text widget
Text(
"Compteur$_counter",
style:TextStyle(
fontWeight: [Link],
fontSize:16,
color: [Link],
),
);
30
The Image widget
[Link]
assets:
assets/image/
Center
child:[Link]("assets/image/
my_image.jpg
)
[Link]('[Link]
31
The Scaffold widget
Scaffold
appBar: AppBar(
title:Text("My app"),
),
body:Center(
child:Text("Home page"),
),
floatingActionButton:FloatingActionButton(
onPressed: () {
clicked
},
child:Icon([Link]),
),
bottomNavigationBar:BottomNavigationBar(
items: [
BottomNavigationBarItem(
label:"home",
icon:Icon([Link])
),
BottomNavigationBarItem
label:"calendar",
icon:Icon(Icons.calendar_today)
),
BottomNavigationBarItem(
label:"contact",
icon:Icon(Icons.contact_mail)
),
],
),
) 32
Thewidgets
ofthelayout
The widget container
Center(
child:Container(
height:100,
width:200
color: [Link],
margin: [Link](20),
child:Center(
child:Text("Home page")
),
),
)
34
The widget padding
Center(
child:Container(
height:100,
width:200,
color: [Link],
margin: [Link](20),
child:Padding(
padding: const [Link](8.0),
child:Container(
color: [Link],
child:Center(
child:Text("Home page")
),
),
),
),
)
35
The column widget
SingleChildScrollView
child:Column(
Container
children: [
height:100,
Container
color: [Link][400],
height:100,
),
color: [Link][900],
Container
),
height:100,
Container
color: [Link][300],
height:100,
),
color: [Link][800],
Container
),
height:100,
Container
color: [Link][200],
height:100,
),
color: [Link][700],
Container
),
height:100,
Container
color: [Link][100],
height:100,
),
color: [Link][600],
),
],
Container
),
height:100,
),
color: [Link][500],
),
36
The column widget
37
The widget row
SingleChildScrollView(
scrollDirection: [Link],
child:Row(
children: [
Container
width:100
height:100,
color: [Link][900],
),
Container
width:100,
height:100,
color: [Link][800],
),
Container
width:100,
height:100,
color: [Link][700],
),
Container
width:100,
height:100,
color: [Link][600],
),
Container
width:100,
height:100, 38
color: [Link][500],
The widget row
39
The ListTile widget
ListTile
leading:FlutterLogo(size:56.0),
title:Text('Two-line ListTile'),
subtitle:Text('Here is a second
line'
trailing: Icon(Icons.more_vert),
)
40
Widgets
relatedto
lists
The ListView widget
ListView(
children: [
Container(
width:100,
height:100,
color: [Link][900],
),
Container
width:100
height:100,
color: [Link][800],
),
Container(
width:100,
height:100,
color: [Link][700],
),
Container
width:100,
height:100,
color: [Link][600],
),
],
)
42
The ListTile widget
ListView(
children: [
ListTile
leading:Icon(Icons.supervised_user_circle),
title:Text("my name"),
subtitle:Text("my job"),
trailing:Icon([Link]),
),
ListTile
leading:Icon(Icons.supervised_user_circle),
title:Text("my name"),
subtitle:Text("my job"),
trailing: Icon([Link]),
),
ListTile
leading:Icon(Icons.supervised_user_circle),
title:Text("my name"),
subtitle:Text("my job"),
trailing:Icon([Link]),
),
],
)
43
Thewidgets
Information
Card
Card
child:Column(
mainAxisSize: [Link],
children: <Widget>[
constListTile
leading:Icon([Link]),
title:Text('The Enchanted Nightingale'),
subtitle:Text('Music by Julie Gable. Lyrics by
Sidney Stein.
),
Row(
mainAxisAlignment: [Link],
children: <Widget>[
TextButton
child:constText('BUY TICKETS'),
onPressed: () {/* ... */},
),
constSizedBox(width:8)
TextButton(
child:constText('LISTEN'),
onPressed: () {/* ... */},
),
constSizedBox(width: 8),
],
),
],
),
45
)
Progress Indicator
Column
mainAxisAlignment:
[Link],
children: [
CircularProgressIndicator()
SizedBox(height:50,),
Linear Progress Indicator()
],
)
46
Tooltip
Tooltip(
message:'I am a Tooltip',
decoration:BoxDecoration(
borderRadius:[Link](25),
gradient:
LinearGradient
colors: <Color>[
[Link].shade900
[Link][400]!
]
),
),
height:50,
padding: const [Link](8.0)
preferBelow:true,
textStyle:constTextStyle(
fontSize:24,
color: [Link]
),
showDuration:Duration(seconds:3),
Hover over the text to show a
tooltip.'),
)
47
AlertDialog
Future<void> _showMyDialog() async {
returnshowDialog<void>(
context:context
barrierDismissible:false,// user must tap button!
builder: (BuildContext context) {
returnAlertDialog(
title:constText('AlertDialog Title'),
content:SingleChildScrollView(
child:ListBody(
children:const<Widget>[
This is a demo alert dialog.
Would you like to approve of this
message?
],
),
),
actions: <Widget>[
TextButton(
child:constText('Approve'),
onPressed: () {
[Link](context).pop();
},
),
],
);
},
);
48
}
Widgets
ofInputandof
selection
TextField
TextField(
decoration:InputDecoration(
border: OutlineInputBorder(
borderRadius:
[Link]([Link](10.0))
),
focusedBorder:OutlineInputBorder(
borderSide:BorderSide(color: [Link]),
borderRadius:
[Link]([Link](10.0))
),
hintText:"your text",
label:Text("label"),
fillColor: Colors.white70
),
)
border:
UnderlineInputBorder()
50
TextField
TextField(
obscureText:true,
decoration:InputDecoration(
border:OutlineInputBorder(),
labelText:'Password',
),
),
TextField(
controller:controller,
obscureText:true,
decoration:InputDecoration(
border: OutlineInputBorder(),
labelText:'Password',
),
),
51
Form
final_formKey=
GlobalKey<FormState>();
Form
key:_formKey,
child:Column(
children: [],
)
)
TextFormField(
ElevatedButton(
decoration:constInputDecoration(
onPressed: () {
border:OutlineInputBorder(),
if(_formKey.currentState!.validate()) {
labelText:'Email',
[Link](context).showSnackBar(
hintText:'Enter Email'
const SnackBar(content: Text('Processing')
),
Data
autovalidateMode:
);
}
[Link]
},
validator: (value) {
child:constText('Submit'),
if(value!.isEmpty) { )
* Required
}else if(![Link]())
{
Check your email
}else
return null;
}, 52
)
Form
Form if(value!.isEmpty) {
key:_formKey, * Required
child:Column( }else if([Link]<6) {
children: <Widget>[ Password should be at least 6
TextFormField characters
decoration:constInputDecoration( }else if([Link]>15) {
border:OutlineInputBorder(), Password should not be
labelText:'Email', greater than 15 characters
hintText:'Enter Email' else
), return null;
validator: (value) { },
if(value!.isEmpty) { ),
* Required constSizedBox(height:16,),
}else if(![Link]()) { ElevatedButton(
Check your email onPressed: () {
else if (_formKey.currentState!.validate())
return null; {
},
), [Link](context).showSnackBar(
const SizedBox(height: 16,) constSnackBar(content:
TextFormField Processing Data
decoration:constInputDecoration( );
border: OutlineInputBorder(), }
labelText:'Password', },
hintText:'Enter secure password' child:constText('Submit'),
), )
obscureText:true, ],
validator: (value) { ), 53
Form
54
Checkbox
Row(
children: [
Checkbox(
checkColor: [Link],
value:isChecked,
onChanged: (bool? value) {
setState(() {
isChecked= value!;
});
},
),
constText("label")
],
),
55
Radio
group 1 group 2
ListTile ListTile
title:constText('A'), title:constText('C'),
leading:Radio<String>( leading:Radio<String>(
value:"a", value:"c",
groupValue:_character, groupValue:_character2,
onChanged: (String? value) { onChanged: (String? value) {
ListTile
setState(() { setState(() {
title:constText('E'),
_character= value!; _character2= value!; leading:Radio<String>(
}); });
value:"e",
}, },
groupValue:_character2,
), ),
onChanged: (String? value) {
), ),
setState(() {
ListTile ListTile
_character2= value!;
title:constText('B'), title:constText('D'),
});
leading:Radio<String>( leading:Radio<String>(
},
value:"b", value:"d",
),
groupValue:_character, groupValue:_character2,
),
onChanged: (String? value) { onChanged: (String? value) {
setState(() { setState(() {
_character= value!; _character2= value!;
}); });
}, },
), ),
), ),
56
Thewidgets
ofButton
ElevatedButton and OutlinedButton
ElevatedButton
onPressed: () {},
style: [Link](
shape:RoundedRectangleBorder(
borderRadius:[Link](30.0),
),
),
child:constText(' Elevated Button', style:TextStyle(fontSize:
18),)
),
constSizedBox(height:12,)
ElevatedButton
onPressed: () {},
Elevated Button
18),)
),
OutlinedButton
onPressed: () {
debugPrint('Received click');
},
child:constText('Click Me'),
)
58
FloatingActionButton and IconButton
const SizedBox(height: 12),
FloatingActionButton
onPressed: () {},
child:const
Icon([Link])
),
constSizedBox(height:12,)
[Link](
onPressed: () {},
label:constText("image"),
icon:constIcon([Link]),
),
IconButton(
onPressed: () {},
icon:constIcon([Link])
),
59
TextButton and InkWell
TextButton(
style: [Link](
textStyle:constTextStyle(fontSize:
20)
),
onPressed: () {},
child:constText('Text'),
)
InkWell(
onTap: () {},
child:const
Text
)
InkWell
onTap: () {},
child:Container(
color: [Link],
child:constText(
Text
TextStyle(color: [Link])
)
)
) 60
Theroads
Navigation to a new page
ElevatedButton
onPressed: () {
[Link](
context
MaterialPageRoute
builder: (context) => SecondRoute()),
);
},
child:constText("click")
)
62
Navigation with named routes
MaterialApp(
title:'Named Routes Demo',
initialRoute:'/',
routes: {
'/': (context) =>constFirstScreen(),widget.
'/second': (context) =>constSecondScreen(),
},
)
)
ElevatedButton(
onPressed: () {
[Link](context,
/second
},
child:constText("click")
)
63
Return to the previous page
ElevatedButton
onPressed: () {
[Link](context);
},
child:constText("Back")
)
64
Data transfer between Widgets
Named routes
Send
[Link](context).pushNamed("/second", arguments:"argument
1
Recover
finalargs =
[Link](context)!.[Link];
Unnamed routes
Send Recover Access StatefulWidget
class MyWidget extends StatefulWidget {
MyWidget( Stringparam1; Text(
param1:"text 1", Stringparam2; widget.param1
param2:"Text 2", MyWidget({ )
)
required this.param1
required this.param2
Access StatelessWidget
});
@override Text(
_MyWidgetState createState() => param1
_MyWidgetState(); )
65
}
Consumption
webs
services
Architecture
API
[Link]
Model Service
[Link]
Interface
67
Architecture
home 68
Model classArticle {
Article({
[Link]
[Link],
[Link],
[Link],
[Link],
[Link],
[Link],
[Link]
});
finalSource?source;
finalString?author;
finalString?title;
finalString?description;
finalString?url;
finalString?urlToImage;
finalDateTime?publishedAt;
finalString?content;
}
69
Model
[Link](Map<String,dynamic> json) =>Article(
source: json["source"] == null ?
null:
[Link](json["source"]),
author: json["author"] ==null?null: json["author"],
title: json["title"] ==null?null: json["title"],
description: json["description"] ==null?
null:
json["description"],
url: json["url"] ==null?null: json["url"],
urlToImage: json["urlToImage"] ==null?
null:
json["urlToImage"],
publishedAt: json["publishedAt"] ==null?
null:
[Link](json["publishedAt"]),
content: json["content"] ==null?null: json["content"],
);
70
Model
Map<String,dynamic> toJson() => {
"source":source==null?null:source!.toJson(),
"author":author==null?null:author,
"title":title==null?null:title,
"description":description==null?null:description,
"url":url==null?null:url,
"urlToImage":urlToImage==null?null:urlToImage,
"publishedAt":publishedAt==null?
null:
publishedAt!.toIso8601String()
"content":content==null?null:content,
};
71
Model
Data dataFromJson(String str) =>[Link]([Link](str));
72
service
install the dependency
[Link]
http
[Link]
dependencies:
run
http: ^0.13.4 flutter pub get
import 'package:http/[Link]' as
http;
73
service
classNewsService{
Future<Data> getAll() async {
varurl = [Link]([Link]
country=us&category=business&apiKey=e0ac43cc665a48aeb762ed7dae8139e9'
);
varresponse = await [Link](url);
print('Response status:${[Link]}');
print('Response body:${[Link]}');
return data from json([Link]);
}
}
Map<String, String> queryParameters = {
"country":"us",
"category":"business",
"apiKey":
e0ac43cc665a48aeb762ed7dae8139e9
};
varurl = Uri(
scheme:'https',
host:'[Link]',
path:'/v2/top-headlines',
queryParameters: queryParameters,
74
);
Interface
NewsServicenewsService=NewsService();
[Link]().then((value) {
print([Link]!.[Link]);
});
OR
75
Interface
NewsService newsService = NewsService();
FutureBuilder(
future:[Link]()
builder: (BuildContext context, AsyncSnapshot snapshot) {
if([Link]) {
returnOnSuccess(
data: [Link],
);
} else if ([Link]) {
returnOnError(
error: [Link](),
);
else {
return constWaiting();
}
},
) 76
Interface
class OnError extends StatelessWidget {
finalStringerror;
OnError({
Key? key,
required [Link]
}) :super(key: key);
@override
Widget build(BuildContext context) {
returnCenter(
child:Column(
mainAxisAlignment: [Link],
children:<Widget>[
constIcon(
Icons.error_outline
color: [Link],
size:60,
),
Padding(
padding: const [Link](top: 16),
child:Text('Error:${error}'),
)
]
)
);
}
}
77
Interface
class Waiting extends StatelessWidget {
constWaiting({
Key? key,
}) :super(key: key);
@override
Widget build(BuildContext context) {
returnCenter(
child:Column(
mainAxisAlignment: [Link],
children:const<Widget>[
SizedBox(
width:60,
height:60,
child:CircularProgressIndicator(),
),
Padding(
padding: [Link](top: 16),
child:Text('Awaiting result...'),
)
]
)
);
}
}
78
Interface
class OnSuccess extends StatelessWidget {
finalDatadata;
OnSuccess({
Key? key,
required [Link]
}) :super(key: key);
@override
Widget build(BuildContext context) {
returnCenter(
child:Column(
mainAxisAlignment: [Link],
children: <Widget>[
constIcon(
Icons.check_circle_outline
color: [Link],
size:60,
),
Padding(
padding:[Link](top:16),
child:Text('Result:$
{[Link]!.[Link]}'},
)
]
),
);
}
} 79
FirebaseCloud
Firestore
Create a Firebase project
81
Integration of Firebase with Android, iOS, and Web
82
Web platform configuration
83
Web platform configuration
84
Web platform configuration
85
Activate Cloud Firestore
• You can enable the Firestore database by selecting Firestore in the
left menu, then by clicking on Create a database.
86
Adding Firebase to Flutter
• firebase_core: required for Firebase initialization and the use of any other plugin
Firebase.
• cloud_firestore: required to interact with the Firestore database.
87
Initialization
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/[Link]';
finalString?id;
finalDateTime?createdAt;
finalStringtitle;
finalStringbody;
90
Display list of documents
import 'package:cloud_firestore/cloud_firestore.dart';
FutureBuilder(
future: [Link]("articles")
.orderBy("createdAt", descending:true)
.get(),
builder: (context, snapshot) {
if([Link]){
returnOnError(message: [Link]());
}else if([Link]){
QuerySnapshot collection = [Link];
returnBuildListArticle(collection: collection);
}
return constCenter(
child:CircularProgressIndicator()
);
}
},
)
91
Show list of documents
import 'package:cloud_firestore/cloud_firestore.dart';
StreamBuilder
stream:[Link]("articles")
.orderBy("createdAt",descending:true)
Snapshots (include metadata changes: true)
builder: (context, snapshot) {
if([Link]){
returnOnError(message: [Link]());
}else if([Link]){
QuerySnapshot collection = [Link]
QuerySnapshot;
returnBuildListArticle(collection: collection);
else{
return constCenter(
child:CircularProgressIndicator()
);
}
},
)
92
Show list of documents
class BuildListArticle extends StatelessWidget {
constBuildListArticle({
Key? key,
required [Link],
}) :super(key: key);
finalQuerySnapshot<Object?>collection;
@override
Widget build(BuildContext context) {
[Link](
itemCount:[Link],
itemBuilder: (context, index) {
Article article = [Link]([Link][index]);
returnItemCard(article: article);
},
);
}
}
93
Display list of documents
class ItemCard extends StatelessWidget {
constItemCard({
Key? key,
required [Link],
}) :super(key: key);
finalArticlearticle;
@override
Widget build(BuildContext context) {
returnPadding(
padding: const [Link](8.0),
child:Card(
elevation:8,
child:Column(
children: [
Align(
alignment: [Link],
child:Text([Link]!.toIso8601String()),
),
ListTile
title:Text([Link]),
subtitle:Text([Link]),
),
],
)
),
);
}
} 94
Display list of documents
class OnError extends StatelessWidget {
finalStringmessage;
constOnError({
Key? key,
[Link],
}) :super(key: key);
@override
Widget build(BuildContext context) {
returnCenter(
child:Text(message,
style:constTextStyle(color: [Link]),
),
);
}
}
95
MR
ECI
FOR YOUR VOTE
ATTENTION