Vous êtes sur la page 1sur 63

F ORMATION C OMPL ÈTE SUR F LUTTER

ENOK-Dev

6 août 2023
Cours Complet Sur Flutter

Table des matières


1 Introduction à Flutter 1
1.1 Qu’est-ce que Flutter ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Avantages de Flutter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

2 Installation et configuration 1
2.1 Installation de Flutter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
2.2 Configuration de l’environnement . . . . . . . . . . . . . . . . . . . . . . . . 2
2.2.1 Configuration pour Android . . . . . . . . . . . . . . . . . . . . . . . 2
2.2.2 Configuration pour iOS . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.2.3 Configuration pour le Web . . . . . . . . . . . . . . . . . . . . . . . . 2

3 Création d’un projet Flutter 3


3.1 Utilisation de la commande flutter create . . . . . . . . . . . . . . . . . . 3
3.2 Structure du projet Flutter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

4 Concepts fondamentaux 3
4.1 Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
4.2 Hot Reload . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
4.3 Comprendre la fonction main() . . . . . . . . . . . . . . . . . . . . . . . . . 1
4.4 Création d’un widget de base . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

5 Exploration des widgets de base 2


5.1 MaterialApp et Scaffold . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
5.2 AppBar et FloatingActionButton . . . . . . . . . . . . . . . . . . . . . . . . . 2
5.3 Text et TextStyle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
5.4 Image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

6 Gestion des mises en page (Layout) 5


6.1 Introduction aux mises en page en Flutter . . . . . . . . . . . . . . . . . . . . 5
6.2 Container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
6.3 Row et Column . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
6.4 ListView . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

7 Gestion des états (State Management) 7


7.1 Introduction à la gestion des états en Flutter . . . . . . . . . . . . . . . . . . . 7
7.2 setState() et Stateful Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
7.3 Provider Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
7.4 Navigation entre les écrans (Routes) . . . . . . . . . . . . . . . . . . . . . . . 1
7.5 Envoi de données à une nouvelle page . . . . . . . . . . . . . . . . . . . . . . 2
7.6 Retour de données de la page précédente . . . . . . . . . . . . . . . . . . . . . 3

8 Interaction avec les utilisateurs 5


8.1 Gestion des gestes (taps, swipes, etc.) . . . . . . . . . . . . . . . . . . . . . . 5
8.2 Dialogs et Snackbars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
8.3 BottomSheet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 1


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

9 Appel d’API et gestion des données 8


9.1 Utilisation de packages pour les appels d’API . . . . . . . . . . . . . . . . . . 8
9.2 Traitement des données JSON . . . . . . . . . . . . . . . . . . . . . . . . . . 9
9.3 Affichage des données dans des widgets . . . . . . . . . . . . . . . . . . . . . 11

10 Thèmes et personnalisation 12
10.1 Utilisation de thèmes pour personnaliser l’apparence . . . . . . . . . . . . . . 12
10.2 Création de thèmes personnalisés . . . . . . . . . . . . . . . . . . . . . . . . . 13

11 Animation et transitions 14
11.1 Introduction aux animations en Flutter . . . . . . . . . . . . . . . . . . . . . . 14
11.2 Utilisation de l’API d’animation Flutter . . . . . . . . . . . . . . . . . . . . . 16

12 Gestion des formulaires 17


12.1 Création de formulaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
12.2 Validation des champs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

13 Gestion des états 22


13.1 Gestion des états avec StatefulWidget . . . . . . . . . . . . . . . . . . . . . . 22
13.2 Gestion des états avec Provider . . . . . . . . . . . . . . . . . . . . . . . . . . 24

14 14. Gestion des formulaires 25


14.1 Création de formulaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
14.2 Validation des champs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

15 15. Publication de l’application 30


15.1 Compilation de l’application pour Android et iOS . . . . . . . . . . . . . . . . 30
15.2 Publication sur les app stores . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

16 16. Flutter pour le Web 31


16.1 Aperçu de la prise en charge du Web avec Flutter . . . . . . . . . . . . . . . . 31
16.2 Différences par rapport au développement pour mobile . . . . . . . . . . . . . 31

17 Configuration de l’environnement 33

18 Création du projet 33

19 Ajout des dépendances 33

20 Configuration des icônes 33

21 Création des modèles 34

22 Création du contrôleur (Controller) 34

23 Création de l’interface utilisateur (UI) 34

24 Introduction 36

25 Configuration du projet 37

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 2


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

26 Installation des dépendances 37

27 Modèle de données Task 37


27.1 États (task state.dart) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

28 Bloc de gestion des tâches 39

29 Écran principal (HomeScreen) 40

30 Point d’entrée de l’application (main.dart) 42

31 Conclusion 42

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 3


TKY 0065@ GMAIL . COM
L ES BASES F LUTTER

Enok-Dev

6 août 2023
Cours Complet Sur Flutter

1 Introduction à Flutter
1.1 Qu’est-ce que Flutter ?
Flutter est un framework open-source développé par Google pour créer des applications
multiplateformes de haute qualité. Il permet de développer des applications mobiles pour An-
droid, iOS et même le Web à partir d’une seule base de code. Flutter utilise le langage de
programmation Dart, qui est également développé par Google.

1.2 Avantages de Flutter


Flutter offre plusieurs avantages significatifs pour le développement d’applications mo-
biles :
— Performances élevées : grâce à son moteur de rendu graphique personnalisé, Flutter offre
des performances rapides et fluides.
— Hot Reload : cette fonctionnalité permet aux développeurs de voir instantanément les
changements apportés au code sans redémarrer l’application, accélérant ainsi le proces-
sus de développement.
— Interface utilisateur déclarative : Flutter utilise une approche déclarative pour la construc-
tion de l’interface utilisateur, ce qui facilite la compréhension et la maintenance du code.
— Widgets riches : Flutter propose une vaste bibliothèque de widgets personnalisables pour
créer des interfaces utilisateur attrayantes.
— Développement multiplateforme : en écrivant une seule base de code, les développeurs
peuvent déployer leurs applications sur Android, iOS et le Web.
— Communauté active : Flutter bénéficie d’une communauté de développeurs active, ce
qui signifie qu’il existe de nombreux packages et ressources disponibles pour faciliter le
développement.

2 Installation et configuration
2.1 Installation de Flutter
Avant de commencer le développement avec Flutter, vous devez installer Flutter sur votre
système. Voici les étapes pour l’installation :
1. Rendez-vous sur le site officiel de Flutter : https://flutter.dev
2. Téléchargez la dernière version de Flutter pour votre système d’exploitation (Windows,
macOS ou Linux).
3. Extrayez l’archive téléchargée dans un répertoire de votre choix.
4. Ajoutez le chemin d’installation de Flutter à votre variable d’environnement PATH pour
pouvoir y accéder depuis n’importe quel répertoire dans votre terminal.
5. Vérifiez l’installation en exécutant la commande suivante dans votre terminal :

flutter doctor

Cette commande vérifie si tout est configuré correctement et vous indique si des dépendances
supplémentaires doivent être installées.

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 1


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

2.2 Configuration de l’environnement


Une fois Flutter installé, vous devez configurer votre environnement de développement pour
cibler les plates-formes souhaitées (Android, iOS, Web). Voici les étapes de configuration pour
chaque plate-forme :

2.2.1 Configuration pour Android


Pour développer des applications Android avec Flutter, vous devez installer Android Studio
et configurer le SDK Android :
1. Téléchargez et installez Android Studio à partir du site officiel : https://developer.
android.com/studio
2. Ouvrez Android Studio et accédez aux ”Préférences” (ou ”Paramètres” sur Windows).
3. Dans le menu ”SDK Manager”, installez les versions Android souhaitées (par exemple
Android 10, Android 11, etc.).
4. Ajoutez le chemin du SDK Android à votre variable d’environnement ANDROID HOME
pour que Flutter puisse le trouver.

2.2.2 Configuration pour iOS


Pour développer des applications iOS avec Flutter, vous devez configurer Xcode :
1. Installez Xcode à partir de l’App Store sur votre Mac.
2. Ouvrez Xcode et acceptez les conditions d’utilisation.
3. Installez les simulateurs iOS souhaités à partir de Xcode ¿ Préférences ¿ Composants.
4. Vérifiez que vous avez accepté la licence Xcode en exécutant la commande suivante dans
votre terminal :

sudo xcodebuild -license

2.2.3 Configuration pour le Web


Pour développer des applications Flutter pour le Web, vous devez activer la prise en charge
du Web dans votre projet :
1. Exécutez la commande suivante dans votre terminal pour activer la prise en charge du
Web :

flutter channel beta


flutter upgrade
flutter config --enable-web

2. Vous pouvez désormais créer des applications Flutter pour le Web en utilisant les mêmes
commandes que pour Android et iOS.

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 2


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

3 Création d’un projet Flutter


3.1 Utilisation de la commande flutter create
Une fois que Flutter est installé et configuré sur votre système, vous pouvez créer un nou-
veau projet Flutter en utilisant la commande flutter create :
flutter create mon_projet_flutter
Cette commande créera un nouveau projet Flutter nommé ”mon projet flutter” avec une
structure de fichiers de base.

3.2 Structure du projet Flutter


La structure de base d’un projet Flutter créé avec la commande flutter create est la
suivante :
— android/ : Ce répertoire contient le code spécifique à Android, y compris le fichier
AndroidManifest.xml et les ressources.
— ios/ : Ce répertoire contient le code spécifique à iOS, y compris le fichier Info.plist
et les ressources.
— lib/ : Ce répertoire contient le code Dart principal de votre application. Le fichier
main.dart est l’entrée de l’application.
— web/ : Ce répertoire contient le code spécifique au Web lorsque la prise en charge du
Web est activée.
— test/ : Ce répertoire contient les fichiers de test pour votre application.
Vous pouvez commencer à développer votre application en modifiant le fichier lib/main.dart
qui contient la fonction main() à partir de laquelle l’application est lancée.

4 Concepts fondamentaux
4.1 Widgets
Dans Flutter, tout est un widget. Un widget est un élément de l’interface utilisateur, tel
qu’un bouton, un champ de texte, une image, une mise en page, etc. Les widgets définissent
la structure et l’apparence de votre application. Il existe deux types de widgets : les widgets
Stateless et les widgets Stateful.
Les widgets Stateless sont des widgets dont l’état ne change pas, ce qui signifie qu’ils sont
immuables. Ils sont utilisés pour afficher des informations statiques dans votre application.
Voici un exemple de widget Stateless affichant un texte :
import ’package:flutter/material.dart’;

class MyTextWidget extends StatelessWidget {


@override
Widget build(BuildContext context) {
return Text(’Hello, World!’);
}
}

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 3


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

Les widgets Stateful, en revanche, peuvent changer d’état au fil du temps, ce qui signifie
qu’ils sont mutables. Ils sont utilisés pour afficher des informations qui peuvent être modifiées.
Voici un exemple de widget Stateful affichant un compteur :

import ’package:flutter/material.dart’;

class MyCounterWidget extends StatefulWidget {


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

class _MyCounterWidgetState extends State<MyCounterWidget> {


int _counter = 0;

void _incrementCounter() {
setState(() {
_counter++;
});
}

@override
Widget build(BuildContext context) {
return Column(
children: [
Text(’Counter: $_counter’),
ElevatedButton(
onPressed: _incrementCounter,
child: Text(’Increment’),
),
],
);
}
}

Dans cet exemple, nous utilisons un widget Stateful pour afficher un compteur qui s’incrémente
à chaque fois que le bouton est pressé.

4.2 Hot Reload


L’une des fonctionnalités les plus puissantes de Flutter est le Hot Reload. Cette fonc-
tionnalité vous permet de voir instantanément les changements que vous apportez au code
sans redémarrer l’application. Cela accélère considérablement le processus de développement,
car vous pouvez expérimenter rapidement différentes modifications et visualiser les résultats
immédiatement.
Pour utiliser Hot Reload, il vous suffit de modifier le code de votre application, puis d’ap-
puyer sur le bouton ”Hot Reload” dans votre IDE ou d’exécuter la commande ”flutter hot
reload” dans votre terminal.

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 4


TKY 0065@ GMAIL . COM
E XPLORATION DES WIDGETS DE BASE

Enok-Dev

6 août 2023
Cours Complet Sur Flutter

4.3 Comprendre la fonction main()


Dans une application Flutter, la fonction main() est le point d’entrée de l’application. C’est
le premier code qui est exécuté lorsque l’application est lancée. La fonction main() appelle la
fonction runApp() pour exécuter le widget racine de l’application.
Voici un exemple de la fonction main() :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

Dans cet exemple, la fonction main() appelle la fonction runApp() en lui passant une
instance de MyApp(), qui est le widget racine de l’application.

4.4 Création d’un widget de base


Pour créer une application Flutter, vous devez créer un widget qui sera le point de départ de
votre interface utilisateur. Ce widget est généralement de type StatelessWidget ou StatefulWidget.
Voici un exemple d’un widget de base MyApp() qui affiche simplement un texte à l’écran :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(
child: Text(’Bienvenue sur Flutter !’),
),
),
);
}
}

Dans cet exemple, nous avons créé un widget MyApp qui est de type StatelessWidget. Le
widget retourne un MaterialApp comme widget racine, qui fournit une structure de base pour
notre application. Le MaterialApp contient un Scaffold qui fournit un appbar et un corps
pour afficher le texte ”Bienvenue sur Flutter !”.

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 1


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

5 Exploration des widgets de base


5.1 MaterialApp et Scaffold
MaterialApp est un widget qui implémente les spécifications de conception Material De-
sign de Google et fournit un point d’entrée pour votre application Flutter. Il doit être utilisé
comme le widget racine de votre application. Scaffold est un widget qui implémente la struc-
ture de base d’une application mobile, comprenant une app bar pour les titres, un corps pour
afficher le contenu principal et bien plus encore.
Voici un exemple d’utilisation de MaterialApp et Scaffold :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(
child: Text(’Bienvenue sur Flutter !’),
),
),
);
}
}

Dans cet exemple, nous avons utilisé MaterialApp comme le widget racine de l’application
et Scaffold pour définir la structure de base de la page, y compris l’app bar avec le titre ”Mon
Application Flutter” et le corps affichant le texte ”Bienvenue sur Flutter !”.

5.2 AppBar et FloatingActionButton


AppBar est un widget qui affiche une barre d’applications en haut de l’écran. Elle est
généralement utilisée pour afficher le titre de l’application et des actions telles que des boutons
de navigation. FloatingActionButton est un widget qui affiche un bouton flottant circulaire
généralement utilisé pour déclencher une action principale dans l’application.
Voici un exemple d’utilisation de AppBar et FloatingActionButton :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 2


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(
child: Text(’Bienvenue sur Flutter !’),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// Action à exécuter lorsque le bouton est pressé
},
child: Icon(Icons.add),
),
),
);
}
}

Dans cet exemple, nous avons ajouté une FloatingActionButton qui affiche une icône
d’ajout (Icon(Icons.add)). Lorsque le bouton est pressé, une action spécifique peut être
exécutée en ajoutant une fonction à l’attribut onPressed du FloatingActionButton.

5.3 Text et TextStyle


Le widget Text est utilisé pour afficher du texte à l’écran. Vous pouvez personnaliser l’ap-
parence du texte en utilisant le widget TextStyle.
Voici un exemple d’utilisation de Text et TextStyle :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 3


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

child: Text(
’Bienvenue sur Flutter !’,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
),
),
);
}
}

Dans cet exemple, nous avons utilisé le widget Text pour afficher le texte ”Bienvenue sur
Flutter !” au centre de l’écran. Nous avons également appliqué un style personnalisé au texte
en utilisant le widget TextStyle, définissant la taille de la police, le poids de la police et la
couleur du texte.

5.4 Image
Le widget Image est utilisé pour afficher des images dans votre application Flutter. Vous
pouvez charger des images à partir de différentes sources telles que le réseau, le disque local
ou les ressources de l’application.
Voici un exemple d’utilisation du widget Image pour afficher une image à partir d’une URL
réseau :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(
child: Image.network(
’https://example.com/mon_image.jpg’,
width: 200,
height: 200,
),
),
),

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 4


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

);
}
}

Dans cet exemple, nous avons utilisé le widget Image.network pour afficher une image à
partir de l’URL ”https ://example.com/mon image.jpg”. Nous avons également défini la largeur
et la hauteur de l’image pour la redimensionner.

6 Gestion des mises en page (Layout)


6.1 Introduction aux mises en page en Flutter
Les mises en page en Flutter sont construites à l’aide de widgets qui définissent comment
les éléments de l’interface utilisateur sont disposés les uns par rapport aux autres. Flutter offre
une grande variété de widgets de mise en page pour vous aider à créer des interfaces utilisateur
dynamiques et réactives.

6.2 Container
Le widget Container est un conteneur rectangulaire qui peut être utilisé pour décorer ou
aligner son enfant. Il peut également être utilisé pour ajouter un remplissage, des marges et des
bordures autour de son enfant.
Voici un exemple d’utilisation du widget Container :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(
child: Container(
width: 200,
height: 200,
color: Colors.blue,
child: Text(’Mon Conteneur’),
),
),
),
);

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 5


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

}
}
Dans cet exemple, nous avons utilisé le widget Container pour créer un conteneur rectan-
gulaire de taille 200x200 avec un fond bleu et affichant le texte ”Mon Conteneur”.

6.3 Row et Column


Les widgets Row et Column sont utilisés pour organiser leurs enfants en ligne (dans le cas
de Row) ou en colonne (dans le cas de Column). Ils sont très utiles pour créer des mises en page
horizontales ou verticales.
Voici un exemple d’utilisation de Row et Column :
import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(’Ligne 1’),
Text(’Ligne 2’),
Text(’Ligne 3’),
],
),
),
),
);
}
}
Dans cet exemple, nous avons utilisé le widget Column pour organiser trois widgets Text
en colonne, avec un espacement égal entre chaque élément.

6.4 ListView
Le widget ListView est utilisé pour afficher une liste de widgets, généralement pour affi-
cher des données qui dépassent la taille de l’écran.
Voici un exemple d’utilisation de ListView :

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 6


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: ListView(
children: [
ListTile(title: Text(’Élément 1’)),
ListTile(title: Text(’Élément 2’)),
ListTile(title: Text(’Élément 3’)),
ListTile(title: Text(’Élément 4’)),
],
),
),
);
}
}

Dans cet exemple, nous avons utilisé le widget ListView pour afficher une liste de quatre
éléments à l’aide de ListTile.

7 Gestion des états (State Management)


7.1 Introduction à la gestion des états en Flutter
La gestion des états en Flutter est un aspect essentiel du développement d’applications, car
les états déterminent comment l’interface utilisateur réagit aux interactions de l’utilisateur et
aux modifications des données.
Flutter propose plusieurs méthodes pour gérer les états, notamment l’utilisation de setState()
avec des widgets Stateful et l’utilisation de packages de gestion d’états tels que Provider.

7.2 setState() et Stateful Widgets


Le widget Stateful est utilisé lorsque vous avez besoin de gérer un état mutable dans votre
application. Lorsqu’un état change, vous pouvez utiliser la méthode setState() pour notifier
Flutter que l’état a été modifié et que l’interface utilisateur doit être mise à jour en conséquence.
Voici un exemple d’utilisation de setState() avec un widget Stateful :

import ’package:flutter/material.dart’;

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 7


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyStatefulWidget(),
);
}
}

class MyStatefulWidget extends StatefulWidget {


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

class _MyStatefulWidgetState extends State<MyStatefulWidget> {


int _counter = 0;

void _incrementCounter() {
setState(() {
_counter++;
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(’Nombre de clics : $_counter’),
ElevatedButton(
onPressed: _incrementCounter,
child: Text(’Cliquez ici’),
),
],
),
),
);
}

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 8


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

Dans cet exemple, nous avons créé un widget StatefulWidget appelé MyStatefulWidget
qui maintient un état counter qui est mis à jour chaque fois que le bouton est cliqué. La
méthode incrementCounter() utilise setState() pour mettre à jour l’état counter et de-
mander à Flutter de reconstruire l’interface utilisateur avec la nouvelle valeur.

7.3 Provider Package


Le package Provider est un moyen puissant de gérer les états dans une application Flutter.
Il permet de fournir et d’accéder facilement à des états à travers l’ensemble de l’arborescence
de widgets sans avoir besoin de reconstruire les widgets en utilisant setState().
Voici un exemple d’utilisation du package Provider :

import ’package:flutter/material.dart’;
import ’package:provider/provider.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => CounterModel(),
child: MaterialApp(
home: MyConsumerWidget(),
),
);
}
}

class CounterModel extends ChangeNotifier {


int _counter = 0;

int get counter => _counter;

void incrementCounter() {
_counter++;
notifyListeners();
}
}

class MyConsumerWidget extends StatelessWidget {


@override
Widget build(BuildContext context) {
final counterModel = Provider.of<CounterModel>(context);

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 9


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

return Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(’Nombre de clics : ${counterModel.counter}’),
ElevatedButton(
onPressed: () => counterModel.incrementCounter(),
child: Text(’Cliquez ici’),
),
],
),
),
);
}
}

Dans cet exemple, nous avons utilisé le package provider pour gérer l’état counter à
l’aide de ChangeNotifier. Le widget ChangeNotifierProvider fournit CounterModel à
travers l’arborescence de widgets, et le widget MyConsumerWidget accède à l’état counter en
utilisant Provider.of<CounterModel>(context) et met à jour l’état en appelant incrementCounter().

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 10


TKY 0065@ GMAIL . COM
NAVIGATION ,I NTERACTION AVEC LES
UTILISATEURS ,A PPEL D ’API ET GESTION
DES DONN ÉES ,T H ÈMES ET
PERSONNALISATION ,A NIMATION ET
TRANSITIONS

Enok-Dev

6 août 2023
Cours Complet Sur Flutter

7.4 Navigation entre les écrans (Routes)


La navigation entre les écrans est une partie essentielle du développement d’applications.
Flutter propose une approche basée sur les routes pour naviguer entre les écrans.
Voici un exemple de navigation entre deux écrans :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: ’/’,
routes: {
’/’: (context) => FirstScreen(),
’/second’: (context) => SecondScreen(),
},
);
}
}

class FirstScreen extends StatelessWidget {


@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(’Premier écran’),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, ’/second’);
},
child: Text(’Aller au deuxième écran’),
),
),
);
}
}

class SecondScreen extends StatelessWidget {


@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 1


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

title: Text(’Deuxième écran’),


),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(’Retour au premier écran’),
),
),
);
}
}

Dans cet exemple, nous avons défini deux écrans : FirstScreen et SecondScreen. Nous
avons utilisé la propriété routes de MaterialApp pour définir les itinéraires (routes) entre
les écrans. Le bouton dans FirstScreen utilise Navigator.pushNamed() pour naviguer vers
SecondScreen, et le bouton dans SecondScreen utilise Navigator.pop() pour revenir à
l’écran précédent.

7.5 Envoi de données à une nouvelle page


Lorsque vous naviguez vers une nouvelle page, vous pouvez également envoyer des données
à cette page. Cela permet de transmettre des informations importantes entre les écrans.
Voici un exemple d’envoi de données à une nouvelle page :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: ’/’,
routes: {
’/’: (context) => FirstScreen(),
’/second’: (context) => SecondScreen(),
},
);
}
}

class FirstScreen extends StatelessWidget {


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

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 2


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

appBar: AppBar(
title: Text(’Premier écran’),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(
context,
’/second’,
arguments: ’Bonjour depuis le premier écran !’,
);
},
child: Text(’Aller au deuxième écran’),
),
),
);
}
}

class SecondScreen extends StatelessWidget {


@override
Widget build(BuildContext context) {
final message = ModalRoute.of(context).settings.arguments as String;

return Scaffold(
appBar: AppBar(
title: Text(’Deuxième écran’),
),
body: Center(
child: Text(message),
),
);
}
}

Dans cet exemple, nous avons utilisé la propriété arguments de Navigator.pushNamed()


pour envoyer la chaı̂ne de texte ”Bonjour depuis le premier écran !” à SecondScreen. Dans
SecondScreen, nous avons utilisé ModalRoute.of(context).settings.arguments pour
récupérer les données envoyées depuis l’écran précédent.

7.6 Retour de données de la page précédente


Lorsque vous revenez de la page précédente, vous pouvez également renvoyer des données
à cette page. Cela permet d’obtenir des résultats de la page de destination.
Voici un exemple de retour de données à la page précédente :

import ’package:flutter/material.dart’;

void main() {

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 3


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: ’/’,
routes: {
’/’: (context) => FirstScreen(),
’/second’: (context) => SecondScreen(),
},
);
}
}

class FirstScreen extends StatelessWidget {


@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(’Premier écran’),
),
body: Center(
child: ElevatedButton(
onPressed: () async {
final result = await Navigator.pushNamed(context, ’/second’);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(’Résultat : $result’),
),
);
},
child: Text(’Aller au deuxième écran’),
),
),
);
}
}

class SecondScreen extends StatelessWidget {


@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(’Deuxième écran’),
),
body: Center(

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 4


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

child: ElevatedButton(
onPressed: () {
Navigator.pop(context, ’Données renvoyées au premier écran !’);
},
child: Text(’Retour au premier écran’),
),
),
);
}
}

Dans cet exemple, nous avons utilisé Navigator.pushNamed() pour aller à SecondScreen.
Dans SecondScreen, lorsque l’utilisateur appuie sur le bouton ”Retour au premier écran”, nous
utilisons Navigator.pop() pour renvoyer la chaı̂ne de texte ”Données renvoyées au premier
écran !” à FirstScreen. Dans FirstScreen, nous utilisons await avec Navigator.pushNamed()
pour attendre le résultat renvoyé par SecondScreen. Nous affichons ensuite ce résultat dans un
SnackBar.

8 Interaction avec les utilisateurs


8.1 Gestion des gestes (taps, swipes, etc.)
Flutter offre une prise en charge intégrée de la gestion des gestes, tels que les taps et les
swipes, sur les widgets interactifs.
Voici un exemple de gestion de tap sur un widget :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(
child: GestureDetector(
onTap: () {
print(’Le widget a été tapé !’);
},
child: Container(
width: 200,
height: 200,

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 5


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

color: Colors.blue,
child: Center(
child: Text(’Appuyez-moi !’),
),
),
),
),
),
);
}
}

Dans cet exemple, nous avons utilisé le widget GestureDetector pour détecter le tap sur
le conteneur. Lorsque l’utilisateur appuie sur le conteneur, le message ”Le widget a été tapé !”
sera affiché dans la console.

8.2 Dialogs et Snackbars


Les dialogs et les snackbars sont des boı̂tes de dialogue contextuelles utilisées pour afficher
des messages importants ou des choix à l’utilisateur.
Voici un exemple d’utilisation de dialogs et de snackbars :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(
child: ElevatedButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(’Confirmation’),
content: Text(’Voulez-vous vraiment continuer ?’),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 6


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

},
child: Text(’Annuler’),
),
TextButton(
onPressed: () {
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(’Action confirmée !’),
),
);
},
child: Text(’Continuer’),
),
],
);
},
);
},
child: Text(’Afficher la bo^
ıte de dialogue’),
),
),
),
);
}
}

Dans cet exemple, nous avons utilisé showDialog() pour afficher une boı̂te de dialogue de
confirmation. Lorsque l’utilisateur appuie sur le bouton ”Continuer”, nous utilisons ScaffoldMessenger.of(c
pour afficher un SnackBar avec le message ”Action confirmée !”.

8.3 BottomSheet
Le widget BottomSheet est utilisé pour afficher une feuille d’action en bas de l’écran,
généralement pour afficher des options supplémentaires à l’utilisateur.
Voici un exemple d’utilisation de BottomSheet :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 7


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

title: Text(’Mon Application Flutter’),


),
body: Center(
child: ElevatedButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
height: 200,
child: Center(
child: Text(’Contenu de la BottomSheet’),
),
);
},
);
},
child: Text(’Afficher la BottomSheet’),
),
),
),
);
}
}

Dans cet exemple, nous avons utilisé showModalBottomSheet() pour afficher une BottomSheet
avec le contenu ”Contenu de la BottomSheet” au centre de l’écran.

9 Appel d’API et gestion des données


9.1 Utilisation de packages pour les appels d’API
Flutter offre une variété de packages qui facilitent les appels d’API depuis votre application.
Vous pouvez utiliser des packages tels que http pour effectuer des requêtes HTTP vers des API
distantes.
Voici un exemple d’appel d’API avec le package http :

import ’package:flutter/material.dart’;
import ’package:http/http.dart’ as http;

void main() {
runApp(MyApp());
}

class MyApp extends StatefulWidget {


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

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 8


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

class _MyAppState extends State<MyApp> {


String _data = ’’;

Future<void> fetchData() async {


final response = await http.get(Uri.parse(’https://api.example.com/data’));
if (response.statusCode == 200) {
setState(() {
_data = response.body;
});
} else {
setState(() {
_data = ’Erreur lors de la récupération des données.’;
});
}
}

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(
child: ElevatedButton(
onPressed: () {
fetchData();
},
child: Text(’Récupérer les données de l\’API’),
),
),
),
);
}
}

Dans cet exemple, nous avons utilisé le package http pour effectuer un appel d’API à
l’URL ”https ://api.example.com/data”. Lorsque l’utilisateur appuie sur le bouton ”Récupérer
les données de l’API”, nous utilisons la fonction fetchData() pour effectuer l’appel d’API et
mettre à jour l’état avec les données reçues.

9.2 Traitement des données JSON


Souvent, les API retournent des données au format JSON. Pour traiter ces données, vous
pouvez utiliser le package dart:convert pour convertir les données JSON en objets Dart.
Voici un exemple de traitement de données JSON :

import ’dart:convert’;

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 9


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

import ’package:flutter/material.dart’;
import ’package:http/http.dart’ as http;

void main() {
runApp(MyApp());
}

class MyApp extends StatefulWidget {


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

class _MyAppState extends State<MyApp> {


List<String> _dataList = [];

Future<void> fetchData() async {


final response = await http.get(Uri.parse(’https://api.example.com/data’));
if (response.statusCode == 200) {
final jsonData = json.decode(response.body);
setState(() {
_dataList = List<String>.from(jsonData);
});
} else {
setState(() {
_dataList = [’Erreur lors de la récupération des données.’];
});
}
}

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(
child: ElevatedButton(
onPressed: () {
fetchData();
},
child: Text(’Récupérer les données de l\’API’),
),
),
),
);
}
}

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 10


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

Dans cet exemple, nous avons utilisé le package dart:convert pour décoder les données
JSON retournées par l’API. Nous avons converti les données JSON en une liste d’objets Dart
et mis à jour l’état avec ces données.

9.3 Affichage des données dans des widgets


Une fois que vous avez récupéré et traité les données depuis une API, vous pouvez les
afficher dans des widgets pour les présenter à l’utilisateur.
Voici un exemple d’affichage des données dans des widgets :

import ’dart:convert’;
import ’package:flutter/material.dart’;
import ’package:http/http.dart’ as http;

void main() {
runApp(MyApp());
}

class MyApp extends StatefulWidget {


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

class _MyAppState extends State<MyApp> {


List<String> _dataList = [];

Future<void> fetchData() async {


final response = await http.get(Uri.parse(’https://api.example.com/data’));
if (response.statusCode == 200) {
final jsonData = json.decode(response.body);
setState(() {
_dataList = List<String>.from(jsonData);
});
} else {
setState(() {
_dataList = [’Erreur lors de la récupération des données.’];
});
}
}

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 11


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
fetchData();
},
child: Text(’Récupérer les données de l\’API’),
),
SizedBox(height: 20),
if (_dataList.isNotEmpty)
Text(’Données récupérées depuis l\’API :’),
for (var data in _dataList)
Text(data),
],
),
),
),
);
}
}

Dans cet exemple, nous avons affiché les données récupérées depuis l’API dans des wid-
gets Text. Si les données ont été récupérées avec succès, nous affichons le message ”Données
récupérées depuis l’API :” suivi de chaque élément de la liste dataList.

10 Thèmes et personnalisation
10.1 Utilisation de thèmes pour personnaliser l’apparence
Flutter propose un système de thèmes qui permet de personnaliser l’apparence de votre
application de manière cohérente.
Voici un exemple d’utilisation de thèmes pour personnaliser l’apparence :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Colors.blue,
accentColor: Colors.yellow,
),

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 12


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

home: Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(
child: Text(
’Personnalisation avec thèmes’,
style: TextStyle(fontSize: 24),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
),
),
);
}
}

Dans cet exemple, nous avons défini un thème pour l’application en utilisant ThemeData.
Nous avons personnalisé les couleurs en définissant primaryColor à Colors.blue et accentColor
à Colors.yellow. Ces couleurs seront utilisées par défaut dans les widgets tels que AppBar et
FloatingActionButton.

10.2 Création de thèmes personnalisés


Vous pouvez également créer des thèmes personnalisés pour une personnalisation plus
avancée de votre application.
Voici un exemple de création de thèmes personnalisés :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
theme: myTheme,
home: Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(
child: Text(
’Personnalisation avec thèmes personnalisés’,
style: TextStyle(fontSize: 24),

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 13


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
),
),
);
}
}

final myTheme = ThemeData(


primaryColor: Colors.purple,
accentColor: Colors.orange,
fontFamily: ’Roboto’,
textTheme: TextTheme(
headline1: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
bodyText1: TextStyle(fontSize: 16),
),
);

Dans cet exemple, nous avons créé un thème personnalisé myTheme en définissant des pro-
priétés telles que les couleurs, la police et le style de texte. Nous avons ensuite utilisé ce thème
dans l’application en l’affectant à la propriété theme de MaterialApp.

11 Animation et transitions
11.1 Introduction aux animations en Flutter
Flutter offre un puissant système d’animation qui vous permet d’animer les propriétés des
widgets pour créer des expériences utilisateur fluides et interactives.
Voici un exemple d’utilisation de l’animation en Flutter :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyAnimatedWidget(),
);
}
}

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 14


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

class MyAnimatedWidget extends StatefulWidget {


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

class _MyAnimatedWidgetState extends State<MyAnimatedWidget>


with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _animation;

@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
);
_animation = Tween<double>(begin: 0, end: 200).animate(_animationController);
}

@override
void dispose() {
_animationController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(
child: AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Container(
width: _animation.value,
height: _animation.value,
color: Colors.blue,
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_animationController.forward();
},

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 15


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

child: Icon(Icons.play_arrow),
),
);
}
}

Dans cet exemple, nous avons utilisé AnimationController pour contrôler l’animation,
et AnimatedBuilder pour animer la taille d’un conteneur. Lorsque l’utilisateur appuie sur le
bouton ”Play”, l’animation démarre et le conteneur augmente progressivement de taille.

11.2 Utilisation de l’API d’animation Flutter


Flutter offre une API d’animation complète qui vous permet de contrôler les transitions
entre les états de vos widgets.
Voici un exemple d’utilisation de l’API d’animation Flutter :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyAnimatedWidget(),
);
}
}

class MyAnimatedWidget extends StatefulWidget {


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

class _MyAnimatedWidgetState extends State<MyAnimatedWidget>


with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _animation;

@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
);
_animation = Tween<double>(begin: 0, end: 200).animate(_animationController);

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 16


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

@override
void dispose() {
_animationController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(
child: AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Container(
width: _animation.value,
height: _animation.value,
color: Colors.blue,
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_animationController.forward();
},
child: Icon(Icons.play_arrow),
),
);
}
}

Dans cet exemple, nous avons utilisé AnimationController pour contrôler l’animation,
et AnimatedBuilder pour animer la taille d’un conteneur. Lorsque l’utilisateur appuie sur le
bouton ”Play”, l’animation démarre et le conteneur augmente progressivement de taille.

12 Gestion des formulaires


12.1 Création de formulaires
Les formulaires sont couramment utilisés pour collecter des données auprès des utilisateurs.
Flutter fournit des widgets pour créer des formulaires facilement.
Voici un exemple de création de formulaire :

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 17


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyForm(),
);
}
}

class MyForm extends StatefulWidget {


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

class _MyFormState extends State<MyForm> {


final _formKey = GlobalKey<FormState>();
String _name = ’’;
int _age = 0;

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
decoration: InputDecoration(labelText: ’Nom’),
validator: (value) {
if (value == null || value.isEmpty) {
return ’Veuillez saisir votre nom.’;
}
return null;
},
onSaved: (value) {
_name = value!;

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 18


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

},
),
TextFormField(
decoration: InputDecoration(labelText: ’^
Age’),
keyboardType: TextInputType.number,
validator: (value) {
if (value == null || value.isEmpty) {
return ’Veuillez saisir votre a^ge.’;
}
final age = int.tryParse(value);
if (age == null || age <= 0) {
return ’Veuillez saisir un a
^ge valide.’;
}
return null;
},
onSaved: (value) {
_age = int.parse(value!);
},
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(’Confirmation’),
content: Text(’Nom : $_name\n^
Age : $_age’),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(’OK’),
),
],
);
},
);
}
},
child: Text(’Valider’),
),
],
),
),

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 19


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

),
);
}
}

Dans cet exemple, nous avons utilisé Form avec deux TextFormField pour collecter le nom
et l’âge de l’utilisateur. Nous avons défini des validateurs pour s’assurer que les champs sont
remplis correctement. Lorsque l’utilisateur appuie sur le bouton ”Valider”, nous vérifions si le
formulaire est valide à l’aide de validate(). Si le formulaire est valide, nous sauvegardons
les données à l’aide de save() et affichons une boı̂te de dialogue de confirmation avec les
informations saisies.

12.2 Validation des champs


Flutter fournit des validateurs pour vérifier si les champs de formulaire sont remplis correc-
tement.
Voici un exemple de validation des champs :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyForm(),
);
}
}

class MyForm extends StatefulWidget {


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

class _MyFormState extends State<MyForm> {


final _formKey = GlobalKey<FormState>();
String _name = ’’;
int _age = 0;

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 20


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

body: Padding(
padding: EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
decoration: InputDecoration(labelText: ’Nom’),
validator: (value) {
if (value == null || value.isEmpty) {
return ’Veuillez saisir votre nom.’;
}
return null;
},
onSaved: (value) {
_name = value!;
},
),
TextFormField(
decoration: InputDecoration(labelText: ’^
Age’),
keyboardType: TextInputType.number,
validator: (value) {
if (value == null || value.isEmpty) {
return ’Veuillez saisir votre a^ge.’;
}
final age = int.tryParse(value);
if (age == null || age <= 0) {
return ’Veuillez saisir un a
^ge valide.’;
}
return null;
},
onSaved: (value) {
_age = int.parse(value!);
},
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(’Confirmation’),
content: Text(’Nom : $_name\n^
Age : $_age’),
actions: [

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 21


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(’OK’),
),
],
);
},
);
}
},
child: Text(’Valider’),
),
],
),
),
),
);
}
}

Dans cet exemple, nous avons utilisé Form avec deux TextFormField pour collecter le nom
et l’âge de l’utilisateur. Nous avons défini des validateurs pour s’assurer que les champs sont
remplis correctement. Lorsque l’utilisateur appuie sur le bouton ”Valider”, nous vérifions si le
formulaire est valide à l’aide de validate(). Si le formulaire est valide, nous sauvegardons
les données à l’aide de save() et affichons une boı̂te de dialogue de confirmation avec les
informations saisies.

13 Gestion des états


13.1 Gestion des états avec StatefulWidget
Flutter utilise le concept de StatefulWidget pour gérer les états des widgets qui peuvent
changer au fil du temps.
Voici un exemple de gestion des états avec StatefulWidget :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyStatefulWidget(),

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 22


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

);
}
}

class MyStatefulWidget extends StatefulWidget {


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

class _MyStatefulWidgetState extends State<MyStatefulWidget> {


int _counter = 0;

void _incrementCounter() {
setState(() {
_counter++;
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
’Nombre de clics :’,
),
Text(
’$_counter’,
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: ’Incrémenter’,
child: Icon(Icons.add),
),
);
}
}
Dans cet exemple, nous avons utilisé StatefulWidget pour créer un widget MyStatefulWidget
qui peut gérer son propre état. Lorsque l’utilisateur appuie sur le bouton flottant, la fonction

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 23


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

incrementCounter() est appelée pour incrémenter le compteur counter, et nous utilisons


setState() pour indiquer à Flutter que l’état a changé. L’interface utilisateur est automati-
quement reconstruite pour refléter la nouvelle valeur de counter.

13.2 Gestion des états avec Provider


Le package provider est largement utilisé pour gérer les états globaux dans une application
Flutter.
Voici un exemple de gestion des états avec provider :

import ’package:flutter/material.dart’;
import ’package:provider/provider.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => CounterProvider(),
child: MaterialApp(
home: MyConsumerWidget(),
),
);
}
}

class CounterProvider with ChangeNotifier {


int _counter = 0;

int get counter => _counter;

void incrementCounter() {
_counter++;
notifyListeners();
}
}

class MyConsumerWidget extends StatelessWidget {


@override
Widget build(BuildContext context) {
var counterProvider = Provider.of<CounterProvider>(context);

return Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 24


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
’Nombre de clics :’,
),
Text(
’${counterProvider.counter}’,
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
counterProvider.incrementCounter();
},
tooltip: ’Incrémenter’,
child: Icon(Icons.add),
),
);
}
}

Dans cet exemple, nous avons créé une classe CounterProvider qui étend ChangeNotifier.
Cette classe contient le compteur counter et une méthode incrementCounter() pour incrémenter
le compteur. Lorsque le compteur est modifié, nous utilisons notifyListeners() pour infor-
mer les consommateurs (MyConsumerWidget) que l’état a changé.
Nous enveloppons l’application avec ChangeNotifierProvider et fournissons une ins-
tance de CounterProvider. Dans MyConsumerWidget, nous utilisons Provider.of<CounterProvider>(co
pour accéder à l’instance de CounterProvider et afficher la valeur du compteur dans l’inter-
face utilisateur. Lorsque l’utilisateur appuie sur le bouton flottant, nous appelons counterProvider.incremen
pour incrémenter le compteur et mettre à jour l’interface utilisateur.

14 14. Gestion des formulaires


14.1 Création de formulaires
Les formulaires sont couramment utilisés pour collecter des données auprès des utilisateurs.
Flutter fournit des widgets pour créer des formulaires facilement. Voici un exemple de création
de formulaire :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 25


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyForm(),
);
}
}

class MyForm extends StatefulWidget {


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

class _MyFormState extends State<MyForm> {


final _formKey = GlobalKey<FormState>();
String _name = ’’;
int _age = 0;

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
decoration: InputDecoration(labelText: ’Nom’),
validator: (value) {
if (value == null || value.isEmpty) {
return ’Veuillez saisir votre nom.’;
}
return null;
},
onSaved: (value) {
_name = value!;
},
),
TextFormField(
decoration: InputDecoration(labelText: ’^
Age’),

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 26


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

keyboardType: TextInputType.number,
validator: (value) {
if (value == null || value.isEmpty) {
return ’Veuillez saisir votre a^ge.’;
}
final age = int.tryParse(value);
if (age == null || age <= 0) {
return ’Veuillez saisir un a
^ge valide.’;
}
return null;
},
onSaved: (value) {
_age = int.parse(value!);
},
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(’Confirmation’),
content: Text(’Nom : $_name\n^
Age : $_age’),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(’OK’),
),
],
);
},
);
}
},
child: Text(’Valider’),
),
],
),
),
),
);
}
}

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 27


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

Dans cet exemple, nous avons utilisé le widget Form avec deux TextFormField pour col-
lecter le nom et l’âge de l’utilisateur. Nous avons défini des validateurs pour s’assurer que les
champs sont remplis correctement. Lorsque l’utilisateur appuie sur le bouton ”Valider”, nous
vérifions si le formulaire est valide à l’aide de validate(). Si le formulaire est valide, nous
sauvegardons les données à l’aide de save() et affichons une boı̂te de dialogue de confirmation
avec les informations saisies.

14.2 Validation des champs


Flutter fournit des validateurs pour vérifier si les champs de formulaire sont remplis correc-
tement.
Voici un exemple de validation des champs :

import ’package:flutter/material.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyForm(),
);
}
}

class MyForm extends StatefulWidget {


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

class _MyFormState extends State<MyForm> {


final _formKey = GlobalKey<FormState>();
String _name = ’’;
int _age = 0;

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(’Mon Application Flutter’),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Form(
key: _formKey,

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 28


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
decoration: InputDecoration(labelText: ’Nom’),
validator: (value) {
if (value == null || value.isEmpty) {
return ’Veuillez saisir votre nom.’;
}
return null;
},
onSaved: (value) {
_name = value!;
},
),
TextFormField(
decoration: InputDecoration(labelText: ’^
Age’),
keyboardType: TextInputType.number,
validator: (value) {
if (value == null || value.isEmpty) {
return ’Veuillez saisir votre a^ge.’;
}
final age = int.tryParse(value);
if (age == null || age <= 0) {
return ’Veuillez saisir un a
^ge valide.’;
}
return null;
},
onSaved: (value) {
_age = int.parse(value!);
},
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(’Confirmation’),
content: Text(’Nom : $_name\n^
Age : $_age’),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 29


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

child: Text(’OK’),
),
],
);
},
);
}
},
child: Text(’Valider’),
),
],
),
),
),
);
}
}

Dans cet exemple, nous avons utilisé le widget Form avec deux TextFormField pour col-
lecter le nom et l’âge de l’utilisateur. Nous avons défini des validateurs pour s’assurer que les
champs sont remplis correctement. Lorsque l’utilisateur appuie sur le bouton ”Valider”, nous
vérifions si le formulaire est valide à l’aide de validate(). Si le formulaire est valide, nous
sauvegardons les données à l’aide de save() et affichons une boı̂te de dialogue de confirmation
avec les informations saisies.

15 15. Publication de l’application


15.1 Compilation de l’application pour Android et iOS
Pour publier une application Flutter sur les app stores, vous devez d’abord la compiler pour
les plateformes cibles, telles qu’Android et iOS.
Pour compiler l’application pour Android, vous devez exécuter la commande suivante dans
le répertoire de votre projet :

flutter build apk

Cette commande générera un fichier APK (Android Package) dans le répertoire ‘build/app/outputs/apk/relea
Ce fichier APK peut être soumis à Google Play Store pour distribution.
Pour compiler l’application pour iOS, vous devez exécuter la commande suivante dans le
répertoire de votre projet :

flutter build ios

Cette commande générera un fichier IPA (iOS App Store Package) dans le répertoire ‘build/ios/iphoneos/‘.
Ce fichier IPA peut être soumis à l’App Store d’Apple pour distribution.

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 30


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

15.2 Publication sur les app stores


Avant de publier votre application sur les app stores, assurez-vous de suivre les directives
et les politiques de soumission d’applications de chaque plateforme (Google Play Store et App
Store d’Apple).
Pour publier votre application sur le Google Play Store, suivez ces étapes générales :
1. Créez un compte développeur sur Google Play Console. 2. Générez une version signée
de l’APK à l’aide de la commande ‘flutter build apk‘. 3. Suivez les étapes de publication dans
Google Play Console, telles que la description de l’application, les captures d’écran, la tarifica-
tion, etc. 4. Soumettez l’APK pour examen et distribution.
Pour publier votre application sur l’App Store d’Apple, suivez ces étapes générales :
1. Créez un compte développeur sur l’Apple Developer Program. 2. Générez une version
signée de l’IPA à l’aide de la commande ‘flutter build ios‘. 3. Créez un nouvel enregistrement
d’application dans App Store Connect, fournissez les détails de l’application et téléchargez les
captures d’écran. 4. Créez un certificat de distribution, un profil de provisionnement et un App
Store Distribution Certificate. 5. Archivez l’application à l’aide de Xcode et soumettez-la pour
examen et distribution.

16 16. Flutter pour le Web


16.1 Aperçu de la prise en charge du Web avec Flutter
Flutter offre une prise en charge expérimentale pour le développement Web. Cela signifie
que vous pouvez créer des applications Flutter qui s’exécutent non seulement sur les appareils
mobiles (Android et iOS) mais aussi sur le Web.
Pour créer une application Flutter pour le Web, vous devez exécuter la commande suivante
dans le répertoire de votre projet :

flutter create .
flutter config --enable-web

Cela mettra à jour votre projet pour activer la prise en charge du Web. Vous pouvez ensuite
exécuter votre application sur le Web en utilisant la commande :

flutter run -d chrome

Notez que la prise en charge du Web avec Flutter est encore en développement et certaines
fonctionnalités peuvent ne pas être complètement prises en charge.

16.2 Différences par rapport au développement pour mobile


Lorsque vous développez une application Flutter pour le Web, il y a certaines différences
par rapport au développement pour les appareils mobiles :
- Widgets : Certaines widgets spécifiques aux plates-formes mobiles peuvent ne pas être
disponibles ou avoir des comportements différents sur le Web. Vous devrez tester votre appli-
cation pour vous assurer que tous les widgets fonctionnent correctement.
- Navigation : Sur le Web, vous utiliserez généralement des URL pour gérer la navigation
entre les pages de votre application, tandis que sur les appareils mobiles, vous utiliserez des
routes.

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 31


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

- Responsive Design : Sur le Web, vous devrez prendre en compte la conception réactive
pour que votre application s’adapte à différentes tailles d’écran, tandis que sur les appareils
mobiles, vous pouvez vous concentrer sur des tailles d’écran spécifiques.
- Plugins : Certains plugins spécifiques aux appareils mobiles peuvent ne pas être dispo-
nibles pour le Web. Vous devrez vérifier la compatibilité des plugins que vous utilisez dans
votre application.
Malgré ces différences, le développement pour le Web avec Flutter offre la possibilité de
partager une grande partie du code avec la version mobile de votre application, ce qui peut
accélérer le développement et réduire les efforts de maintenance.

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 32


TKY 0065@ GMAIL . COM
Projet de Gestion des Tâches avec Flutter et GetX
Enok-Dev
6 août 2023

17 Configuration de l’environnement
Assurez-vous d’avoir installé Flutter sur votre système. Vous pouvez vérifier l’installation
en exécutant flutter doctor dans le terminal.

18 Création du projet
Créez un nouveau projet Flutter en exécutant flutter create task manager dans le
terminal.

19 Ajout des dépendances


Ouvrez le fichier pubspec.yaml et ajoutez les dépendances nécessaires pour GetX et les
icônes de Material Design.

dependencies:
flutter:
sdk: flutter
get: ^4.3.8
flutter_launcher_icons: ^0.9.2

dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^1.0.0
flutter_launcher_icons: ^0.9.2

Exécutez ensuite flutter pub get pour télécharger les dépendances.

20 Configuration des icônes


Pour personnaliser les icônes de l’application, vous pouvez ajouter vos propres icônes dans
le répertoire assets/ et mettre à jour le fichier pubspec.yaml pour les inclure.
Exemple :

33
Cours Complet Sur Flutter

flutter_icons:
android: true
ios: true
image_path: "assets/icon/app_icon.png"

21 Création des modèles


Créez le modèle de tâche qui représentera une tâche dans l’application.

class Task {
final int id;
final String title;
final bool isCompleted;

Task({required this.id, required this.title, this.isCompleted = false});


}

22 Création du contrôleur (Controller)


Créez le contrôleur qui gérera l’état et les actions liées aux tâches.

import ’package:get/get.dart’;
import ’package:task_manager/models/task_model.dart’;

class TaskController extends GetxController {


var tasks = <Task>[].obs;

void addTask(String title) {


tasks.add(Task(id: tasks.length, title: title));
}

void toggleTaskStatus(int taskId) {


tasks[taskId].isCompleted = !tasks[taskId].isCompleted;
}

void deleteTask(int taskId) {


tasks.removeWhere((task) => task.id == taskId);
}
}

23 Création de l’interface utilisateur (UI)


Créez l’interface utilisateur pour afficher les tâches et permettre à l’utilisateur d’ajouter,
supprimer et marquer les tâches comme terminées.

import ’package:flutter/material.dart’;
import ’package:get/get.dart’;

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 34


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

import ’package:task_manager/controllers/task_controller.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


final TaskController _taskController = Get.put(TaskController());

@override
Widget build(BuildContext context) {
return MaterialApp(
title: ’Task Manager’,
home: TaskManagerScreen(),
);
}
}

class TaskManagerScreen extends StatelessWidget {


final TextEditingController _taskTitleController = TextEditingController();

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(’Task Manager’),
),
body: Padding(
padding: EdgeInsets.all(16),
child: Column(
children: [
Row(
children: [
Expanded(
child: TextField(
controller: _taskTitleController,
decoration: InputDecoration(
hintText: ’Ajouter une t^
ache’,
),
),
),
ElevatedButton(
onPressed: () {
if (_taskTitleController.text.isNotEmpty) {
Get.find<TaskController>().addTask(_taskTitleController.text);
_taskTitleController.clear();
}
},

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 35


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

child: Text(’Ajouter’),
),
],
),
SizedBox(height: 16),
Expanded(
child: Obx(
() => ListView.builder(
itemCount: Get.find<TaskController>().tasks.length,
itemBuilder: (context, index) {
final task = Get.find<TaskController>().tasks[index];
return ListTile(
title: Text(task.title),
leading: Checkbox(
value: task.isCompleted,
onChanged: (value) {
Get.find<TaskController>().toggleTaskStatus(index);
},
),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
Get.find<TaskController>().deleteTask(index);
},
),
);
},
),
),
),
],
),
),
);
}
}

Gestion des tâches avec Flutter et Bloc Enok-Dev 6 août 2023

24 Introduction
Dans ce cours, nous allons apprendre à créer une application de gestion des tâches en utili-
sant le framework Flutter avec le pattern Bloc. Le pattern Bloc est un moyen puissant de gérer
l’état de l’application et de séparer la logique métier de l’interface utilisateur.

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 36


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

25 Configuration du projet
Assurez-vous d’avoir installé Flutter sur votre système et configuré l’environnement de
développement. Vous pouvez vérifier cela en exécutant flutter doctor dans votre terminal.
Créez un nouveau projet Flutter en utilisant la commande flutter create task manager.

26 Installation des dépendances


Pour implémenter le pattern Bloc dans notre projet, nous aurons besoin des dépendances
suivantes : - flutter bloc : Fournit les classes pour implémenter le pattern Bloc dans Flutter.
- equatable : Permet de comparer les objets de manière plus efficace.
Pour les ajouter à notre projet, ouvrez le fichier pubspec.yaml et ajoutez les lignes sui-
vantes sous la section dependencies :

dependencies:
flutter:
sdk: flutter
flutter_bloc: ^7.2.3
equatable: ^2.0.0

Enregistrez le fichier, puis exécutez flutter pub get dans votre terminal pour récupérer
les dépendances.

27 Modèle de données Task


Créez un fichier task.dart dans le répertoire models pour définir notre modèle de données
Task :

class Task {
final int id;
final String title;
final bool isCompleted;

Task({required this.id, required this.title, this.isCompleted = false});


}
\en{verbatim}

\section{Événements et États du Bloc}

Dans le répertoire \texttt{bloc}, nous aurons deux fichiers pour définir les événement

\subsection{Événements (task\_event.dart)}

\begin{verbatim}
import ’package:equatable/equatable.dart’;

abstract class TaskEvent extends Equatable {


const TaskEvent();

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 37


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

@override
List<Object> get props => [];
}

class AddTask extends TaskEvent {


final String title;

AddTask(this.title);

@override
List<Object> get props => [title];
}

class ToggleTaskStatus extends TaskEvent {


final int taskId;

ToggleTaskStatus(this.taskId);

@override
List<Object> get props => [taskId];
}

class DeleteTask extends TaskEvent {


final int taskId;

DeleteTask(this.taskId);

@override
List<Object> get props => [taskId];
}

27.1 États (task state.dart)


import ’package:equatable/equatable.dart’;
import ’package:task_manager/models/task.dart’;

abstract class TaskState extends Equatable {


const TaskState();

@override
List<Object> get props => [];
}

class TaskInitial extends TaskState {}

class TaskLoading extends TaskState {}

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 38


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

class TaskLoaded extends TaskState {


final List<Task> tasks;

TaskLoaded(this.tasks);

@override
List<Object> get props => [tasks];
}

class TaskError extends TaskState {


final String message;

TaskError(this.message);

@override
List<Object> get props => [message];
}

28 Bloc de gestion des tâches


Dans le répertoire bloc, créez un fichier task bloc.dart pour implémenter le Bloc de
gestion des tâches :

import ’package:flutter_bloc/flutter_bloc.dart’;
import ’package:task_manager/bloc/task_event.dart’;
import ’package:task_manager/bloc/task_state.dart’;
import ’package:task_manager/models/task.dart’;

class TaskBloc extends Bloc<TaskEvent, TaskState> {


List<Task> tasks = [];

TaskBloc() : super(TaskInitial());

@override
Stream<TaskState> mapEventToState(TaskEvent event) async* {
if (event is AddTask) {
yield TaskLoading();
try {
tasks.add(Task(id: tasks.length, title: event.title));
yield TaskLoaded(tasks);
} catch (e) {
yield TaskError("Erreur lors de l’ajout de la t^
ache.");
}
} else if (event is ToggleTaskStatus) {
yield TaskLoading();
try {
tasks[event.taskId].isCompleted =
!tasks[event.taskId].isCompleted;

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 39


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

yield TaskLoaded(tasks);
} catch (e) {
yield TaskError("Erreur lors du basculement de l’état de la t^
ache.");
}
} else if (event is DeleteTask) {
yield TaskLoading();
try {
tasks.removeWhere((task) => task.id == event.taskId);
yield TaskLoaded(tasks);
} catch (e) {
yield TaskError("Erreur lors de la suppression de la t^ache.");
}
}
}
}

29 Écran principal (HomeScreen)


Créez un fichier home screen.dart dans le répertoire screens pour définir l’écran prin-
cipal de notre application :

import ’package:flutter/material.dart’;
import ’package:flutter_bloc/flutter_bloc.dart’;
import ’package:task_manager/bloc/task_bloc.dart’;
import ’package:task_manager/bloc/task_event.dart’;
import ’package:task_manager/bloc/task_state.dart’;
import ’package:task_manager/models/task.dart’;

class HomeScreen extends StatelessWidget {


final TextEditingController _taskTitleController = TextEditingController();

@override
Widget build(BuildContext context) {
final TaskBloc taskBloc = BlocProvider.of<TaskBloc>(context);

return Scaffold(
appBar: AppBar(
title: Text(’Task Manager’),
),
body: Padding(
padding: EdgeInsets.all(16),
child: Column(
children: [
Row(
children: [
Expanded(
child: TextField(
controller: _taskTitleController,

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 40


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

decoration: InputDecoration(
hintText: ’Ajouter une t^ache’,
),
),
),
ElevatedButton(
onPressed: () {
if (_taskTitleController.text.isNotEmpty) {
taskBloc.add(AddTask(_taskTitleController.text));
_taskTitleController.clear();
}
},
child: Text(’Ajouter’),
),
],
),
SizedBox(height: 16),
BlocBuilder<TaskBloc, TaskState>(
builder: (context, state) {
if (state is TaskLoading) {
return CircularProgressIndicator();
} else if (state is TaskLoaded) {
return Expanded(
child: ListView.builder(
itemCount: state.tasks.length,
itemBuilder: (context, index) {
final Task task = state.tasks[index];
return ListTile(
title: Text(task.title),
leading: Checkbox(
value: task.isCompleted,
onChanged: (_) {
taskBloc.add(ToggleTaskStatus(index));
},
),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
taskBloc.add(DeleteTask(index));
},
),
);
},
),
);
} else if (state is TaskError) {
return Text(’Erreur : ${state.message}’);
} else {

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 41


TKY 0065@ GMAIL . COM
Cours Complet Sur Flutter

return Text(’Aucune t^
ache pour le moment.’);
}
},
),
],
),
),
);
}
}

30 Point d’entrée de l’application (main.dart)


Configurez le point d’entrée de l’application en utilisant BlocProvider pour profiter des
fonctionnalités du Bloc :

import ’package:flutter/material.dart’;
import ’package:flutter_bloc/flutter_bloc.dart’;
import ’package:task_manager/bloc/task_bloc.dart’;
import ’package:task_manager/screens/home_screen.dart’;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => TaskBloc(),
child: MaterialApp(
title: ’Task Manager’,
home: HomeScreen(),
),
);
}
}

31 Conclusion
Félicitations ! Vous avez terminé la création de l’application de gestion des tâches en utili-
sant Flutter avec le pattern Bloc. Vous avez appris à implémenter un Bloc de gestion des tâches,
à séparer la logique métier de l’interface utilisateur et à afficher les tâches dans l’écran prin-
cipal. Vous pouvez maintenant exécuter votre application et commencer à ajouter, cocher et
supprimer des tâches.

Formateur : E NOK -D EV I NG ÉNIEUR S YST ÈME D ’I NFORMATION page 42


TKY 0065@ GMAIL . COM

Vous aimerez peut-être aussi