Flutter
Développement mobile
Développement mobile
●
Le marché des smartphones et appareils mobiles représentant une forte
valeur, les GAFAM ont mis à la disposition des développeurs de nombreux
outils et langages.
●
Les langages existants
– Android : Java puis Kotlin
– Apple : objective-c puis swift
●
Des langages et frameworks multiplateformes sont ensuite apparus
– ionic
– xamarin
Les langages
●
Le souci de Ionic et Xamarin est qu'ils ne fournissent pas une application
native
– le rendu de l'application peut être éloigné des standards de la
plateforme cible (Apple ou Android)
– Les applications sont plus lourdes
– L'accès aux capteurs du smartphone peut être limité
●
Nouvelles technologies
– React Native
– Flutter
Les langages
●
React Native
– React Native utilise le langage javascript. Il est donc plus familier pour
certains développeurs
– Les performances peuvent être décevantes
●
Flutter
– Look & Feel adaptés à la plateforme cible (Les widgets adoptent l'UI
Android ou Apple selon la cible)
– Performances élevés (application réactive)
– Taille d'applications moins importante qu'avec React Native
Flutter
●
Flutter utilise le langage Dart en ajoutant la notion de widget
●
Les widgets sont les éléments de l'interface (UI) comme les boutons, les icônes,
les champs de formulaire,…
●
Chaque widget est responsable de son rendu et de son comportement ←
indépendance forte
●
On peut combinés des widgets entre-eux pour en faire un widget composé
●
Syntaxe proche du C, javascript,…
●
Quelques spécificités
– Paramètres nommés
– Type générique
– async
Ecosystème Flutter
●
Un IDE : Android Studio
●
Un langage performant : Dart
●
Des extensions (+5000) : pubdev
●
Widgets : Documentation avec exemples, Liste des widgets
●
Inspection et debogage : DevTools
●
Publication des applications mobiles : Google Play Console
●
Accès natif aux capteurs du smartphone : Sensors
●
Accès à l'écosystème Google : Maps, Firebase (BDD, Authentification,
messagerie, crashlytics, ...)
Flutter – paramètres nommés
●
POO "classique"
– Constructeur : Center(Key key, double widthFactor) {...}
– Instanciation : Center('a7befd784', 7.6)
●
Sous Flutter, tous les paramètres des widgets sont nommés
– Constructeur : Center({Key? key, double? widthFactor}) {...}
– Instanciation : Center(widthFactor: 7.6)
Android Studio
Paramétrage JVM
●
Augmenter la RAM disponible
pour la JVM peut permettre
d'améliorer la vitesse
Dart
Dart - Particularités
●
Constructeurs
– Dart permet d'avoir des constructeurs qui ne prennent pas le nom de la
classe
– factory : copyWith, from,...
●
Opérateur flèche (arrow operator, lambda function)
– L'opérateur => est utilisé lorsqu'une méthode n'est constitué que d'une
seule instruction qui peut retourner une valeur
int sum(int num1, int num2) => num1 + num2;
– Equivalent à int sum(int num1, int num2) {return num1+num2;}
Exercice - Mastermind
●
L'ordinateur choisit un nombre entre 1000 et 9999. Vous devez trouver le
chiffre choisit avec le moins de coup possible
●
Si vous trouvez un chiffre mais au mauvais endroit, le programme répond
bull
●
Si vous trouvez un chiffre au bon endroit, le programme répond cow
●
Indiquez le nombre d'essai et le nombre de bulls et cows
●
Voir random, stdout et [Link]
Exercice - birthday
●
Faire une liste (tableau) contenant le nom et la date de naissance
d'informaticien célèbre
●
Afficher la liste connu
●
Lorsque l'utilisateur tape le nom d'une personne, la date de naissance est
affichée
Collections Dart
Collections
●
Pour typer les informations stockées dans les collections, Dart utilise les
types génériques <T>
●
Il existe un grand nombre de collections
– Set : collection non ordonnée d'éléments unique
– Queue : Liste FIFO
– Stack : pile FIFO
– List : équivalent d'un tableau
– Map : dictionnaire clé=>valeur
●
Un grand nombre d'opérations sont disponible pour ces collections
– itération (for), generate, contains, add, remove, ...
–
List et Map : Collections les plus utilisées en Flutter
●
Les tableaux = List
– List<int> numbers = [1, 2, 3, 4];
– print(numbers[0]) ;
●
Les tableaux associatifs = Map
– Map<String, int> ages = {"Lucas" : 20, "Leo" : 22};
– print(Map["Lucas"]) ;
●
dynamic si le type peut être différent pour les éléments stockés
– Map<String, dynamic> json = {"nom" :"Lucas", age:20};
Exercice
●
Soit deux listes
– listeA : 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
– listeB : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13
●
Ecrire un programme qui retourne la liste qui contient les éléments
communs à listeA et listeB (sans les duplicats)
●
Voir List, Set, for (ou forEach)
Exercice
●
Créez une classe Student (nom, prénom, age)
– L'âge est optionnel
●
Créez une constructeur paramétré
●
Créez un constructeur nommé (fromJson)
●
Les instances de l'objet Student seront mis dans une liste
●
Une boucle for sera utilisé pour afficher la liste des étudiants dans la
console
StatelessWidget et StatefulWidget
StatelessWidget StatefulWidget
●
un StatelessWidget est un widget ●
un StatefulWidget est un widget
immuable mutable
●
Les éléments visuels sont définis
●
Il peut être modifié dynamiquement
en réponse à des interactions
à l'instanciation utilisateur, des évènements, ...
●
Pas de mémoire pour stocker un ●
Il est composé de deux classes
état – StatefulWidget
– un état (State)
Création d'un projet Flutter
●
Fichier -> New -> New Flutter Project...
●
Flutter permet de créer des applications natives Linux, Windows, MacOS,
Andoid, iPhone, Application Web
●
Créer un Mobile virtuel
– Tools->Device Manager
●
Activer le mode développeur d'un smartphone
– [Link]
ceder-au-mode-developpeur-sur-android
Device Manager
StatelessWidget
StatefulWidget – Le widget
StatefulWidget – gestion de l'état
Flutter
●
Les widgets permettent de respecter le Material Design introduit par
Google. Pour les applications (mobile, web, desktop), l'utilisateur retrouvera
une uniformité d'usage dans les applications.
●
Quelques principes de bases du Material Design
– Hiérarchie visuelle pour indiquer l'importance relative des éléments
– Animations légères pour le dynamisme de l'application lors des
transitions
– Icônes et images claires
●
Une application qui s'éloigne trop des concepts UI/UX de Google peut être
refusée lors de la demande d'ajout au store
Widgets
●
Les widgets sont divisés en deux catégories principales : les widgets de
base et les widgets composites.
●
Les widgets de base sont des éléments simples qui peuvent être utilisés
tels quels ou combinés pour créer des interfaces utilisateur plus complexes.
– Ces widgets sont utilisés pour définir des éléments visuels de base dans l'interface utilisateur. Ils
sont souvent les briques de construction de base pour créer des mises en page et des éléments
d'interface.
●
Les widgets composites sont des widgets qui regroupent plusieurs widgets
de base ou d'autres widgets composites pour créer des structures plus
complexes.
– Ces widgets sont utilisés pour structurer l'application, définir la disposition globale, et regrouper
des éléments d'interface utilisateur pour créer des composants réutilisables et organisés.
Widget de Base
Widget de base
●
Widget de Mise en page ●
Widget d'Affichage
– Container – Text
– Row – RichText
– Column – Image
– ListView – Icon
– GridView
– Stack
– Center
Widget de base
●
Widget de Saisie ●
Widget d'Affichage de Contenu
– TextField – Card
– Checkbox – Tooltip
– Radio – Divider
– Switch – Expanded
– Slider – Spacer
– DropdownButton – SizedBox
Widgets Composites
Widgets Composites
●
Widgets de Navigation ●
Widgets de Dialogue
– AppBar – AlertDialog
– BottomNavigationBar – SimpleDialog
– Drawer – BottomSheet
– TabBar
●
Widgets d'Ecran ●
Widgets de Défilement
– Scaffold – SingleChildScrollView
– TabBarView – ListView
– NestedScrollView – GridView
Widgets Composites
●
Widgets de Formulaires ●
Widgets de Gestion de l'Etat
– Form – StatefulWidget
– FormField – StatelessWidget
– TextFormField – InheritedWidget
– State
●
Widgets d'Animation
– Provider
– AnimatedContainer
– Hero
– TweenAnimationBuilder
Widgets
●
Cette liste n'est pas exhaustive
●
Il est possible de créer des widgets personnalisés en combinant des
widgets de base et composite existants.
MaterialApp - La fondation
●
void main() => runApp(__widget__);
●
Pour __widget__, utiliser un widget Text()
MaterialApp - La fondation
●
Pour une application disposant d'un menu, d'un système de navigation
(routeur), d'un thème personnalisable, le widget de base sera souvent le ou
Scaffold Widget MaterialApp ou Scaffold
Première application
●
Le dossier lib contient les fichiers de notre application
●
Choisissez une plateforme cible
– Pour les ordinateurs peu puissants, évitez
l'émulateur mobile.
●
Lancer l'application
– Android Studio : Run
– VS Code : En ligne de commande -> Flutter run
●
Les applications Flutter supporte le hot reload
Analyse du code
●
import : déclaration des fichiers utilisés par
l'application
– flutter/[Link] permet d'utiliser les
widgets de base
●
main
●
class MyApp
– La classe MyApp dérive d'un
StatelessWidget
– Un StatelessWidget est un widget qui
ne changera pas d'aspect graphique
pendant la vie de l'application
L'arbre des widgets
Utilisation de l'inspecteur
●
On peut modifier certains paramètres
depuis l'inspecteur qui seront visibles dans
l'application
●
Exemple
– Cliquez sur Column
– Modifiez l'espacement entre les widgets
présents dans la colonne
Analyse du code
●
La méthode build est obligatoire et permet au widget de s'afficher
●
L'objet MaterialApp est l'infrastructure de base. Il fournit
– Une barre de navigation
– Un gestionnaire de route
– Un Thème
– Un ancr age pour afficher les éléments graphiques (home)
Analyse de code
●
La classe MyHomePage est un StatefulWidget. Cela signifie qu'il contient
des éléments graphiques et/ou des données qui pourront changer pendant
la vie de l'application
●
Le widget contient une méthode createState() obligatoire. Cette méthode
createState() renvoie une instance qui construit le widget à modifier
(MyHomePageState)
●
La classe MyHomePageState stocke les éléments qui permettent de
modifier la page
●
Sur un StatefulWidget, c'est la méthode setState() qui informe le widget qu'il
doit se redessiner
Exercice
●
Reprendre le code de l'application en séparant la déclaration des deux
objets Stateful et Stateless dans deux fichiers différents.
●
Remplacer le Widget Column par un Widget Row
●
Ajouter un Widget Expanded entre les 2 textes
●
Remplacer le Widget Center par un Widget Container
●
Rajouter une marge au Container
●
Faire apparaître le texte en haut de l'écran
●
Déployer le projet sur un dépôt git
Première Application
●
Créer une Listview dans l'application en modifiant le code par défaut
ListView "statique"
●
Dans une ListView statique, on connaît à l'avance le nombre d'éléments
présent dans la liste (exemple : un menu)
●
Dans le projet, ajoutez un ListView
●
On modifie le style de cet item
●
Exercice : modifier ensuite la
police et la taille du texte
●
children est un tableau avec
la liste des items de la
ListView
ListView "statique"
●
Ajouter un ListTile dans la liste des éléments de la ListView
●
Problème !
– L'application affiche un message d'erreur sur le fait que l'élément ne
peut pas être ajouté.
– Dans l'arbre des widgets, il faut un objet dérivé de Material pour que les
enfants sachent comment et ou se dessiner
– Dérivé de Material :
○
Card, Dialog, Drawer, Scaffold, MaterialApp
– => Englober la ListView dans une instance de Scaffold
ListView "statique"
●
Exercice :
– Ajouter un avatar (un
texte) dans un cercle,
une icône et sous-titre
aux ListTile
Listview "dynamique"
●
Pour une listview dynamique, on ne connaît pas le nombre d'éléments
constitutifs initiaux la liste pourrait provenir d'une API ou d'un système
extérieur)
●
On utilise un Builder dans un state pour alimenter les éléments de la
listview
●
Créer une application permettant d'afficher une liste dont les items seront
une Liste des étudiants
●
Dans l'exemple, il n'est pas nécessaire d'utiliser un StatefulWidget. Dans
une véritable application, les items pourraient être retrouvés depuis une
API. Le StatefulWidget serait alors plus adapté.
●
Modifier la structure de données pour associé à chaque étudiant une
couleur.
Les assets
●
Les assets sont des fichiers statiques que l'on embarque dans l'application.
Les assets les plus courants sont :
– les images
– des polices de caractères
– des textes
– des fichiers json
●
Par convention, les assets sont ajoutées dans le dossier assets du projet
●
Par convention, le dossier assets se trouve à la racine du projet
Exercice
●
Ajoutez une image sur la page de l'application en cours
Les assets
●
Attention aux chemins et à bien déclarer le fichier
Widgets
Manipulation de quelques widgets
Container
●
Le container est un simple bloc rectangulaire qui peut contenir un enfant.
●
On peut lui spécifier un margin et un padding
●
On peut lui spécifier sa hauteur et sa largeur.
●
Il tente toujours de se contraindre à prendre le minimum de place tout en
contenant son enfant
●
Exercice : Faire un conteneur rouge au centre de la page avec le texte
"Containeur"
●
Spécifier une largeur (width) de 100 puis de 1000
Drawer
●
Le widget Drawer permet d'ajouter un menu qui s'affiche suite à un clic sur
le menu "burger" de l'appBar
●
L'icône du menu burger est géré par le Drawer.
– Dans le Drawer, on ajoute généralement
○
un DrawerHeader : en-tête de menu
○
une ListView qui contiendra les différents menus
●
Exercice : Créez un Drawer en ajoutant votre avatar généré sur [Link]
[Link]/#generateur qui sera dans un ovale
Exercice : Widget personnalisé
●
Créer un widget ayant les bords arrondi (Card) contenant un texte et deux
boutons en dessous du texte
●
Ajouter ce widget dans la ListView (15 items)
Polices et ThemeData
●
Flutter gère les polices .ttf (True Type Fonts) et .otf (Open Type Fonts)
●
ttf
– Plus légère
– Généralement plusieurs fichiers selon le style (regular, bold, italic)
●
otf
– Gère des fonctionnalités avancées (glyphe alternatives pour certains
caractères, ligature complexes, caractères spéciaux)
●
Google met à disposition une grande quantité de polices
Polices et ThemeData
●
Style de police
– Serif : Elles ont un empattement à la fin des caractères. Cela guide l’œil
pour les caractères suivants. Important pour les textes imprimés (Times)
– Sans-serif : Pas d'empattement. Ligne plus nette et moderne. Plus
lisible à l'écran (Arial)
– Monospace : Chasse fixe. Tous les caractères occupent la même largeur
(Console)
– Display : Stylisées et décoratives (Pour les titres par exemple) (Lobster)
– Symbol : Les caractères sont des icones ou pictogrammes (Webdings)
– Script : Imite l'écriture humaine
– ......
●
Sur le site Google Fonts, Télécharger la police Tangerine
●
Dézipper le fichier dans le dossier assets/fonts/ du projet
●
Mettre à jour le fichier [Link]
●
Modifié la propriété style du texte
●
Si on utilise le même style sur plusieurs pages, il est préférable d'utiliser le
ThemeData ou des Widgets personnalisé que l'on aura stylisé
●
ThemeData
– ThemeData dispose de plusieurs propriétés que l'on peut ensuite
passer en argument lorsqu'on l'instancie
●
Widget personnalisé
–
Navigation
La navigation
●
La navigation est gérée par deux API
– Navigator
– Router
●
Le navigateur garde la pile des appels des pages et du contexte associée.
On peut alors utiliser le bouton "Retour" du smartphone.
●
Nous verrons deux systèmes de navigation. Pour en savoir plus, voir la
page medium qui détaille bien les différentes routes.
Navigation
●
Un objet Navigator est instancié par les descendants de MaterialApp
(Scaffold, Drawer,...). Il peut être utilisé par tous les Widgets de l'arbre
descendant
●
Pour que le widget puisse proposer une interaction de changement de page
avec l'utilisateur, il doit disposer d'une propriété
– onTap, onPressed
– onDoubleTap
– onLongPressed
●
Les widgets qui disposent de ces propriétés sont :
– Les boutons (TextButton, ElevatedButton,...)
– ListTile (ListTile, ExpansionTile,...)
Navigation
●
Si le widget ne dispose pas d'une des propriétés pouvant réagir à
l'interaction de l'utilisateur, on peut lui adjoindre un widget InkWell ou
l'englober dans un widget GestureDetector.
●
InkWell rajoute un retour visuel à l'utilisateur sous la forme d'une vague
colorée qui parcourt le widget
●
GestureDetector ne fait pas de retour visuel mais permet de gérer plus
finement l'interaction (par exemple glisser/déposer)
Navigator
Navigator
●
Ajouter ce code sur un widget ListTile de la ListView
●
En exercice
– Déplacez la page présente dans [Link] dans le dossier screens
– Essayez de comprendre le code de la propriété onTap (fonction
anonyme)
–
Navigator
●
La méthode push du navigateur prend en paramètre la page (un widget)
vers lequel il faut rediriger l'utilisateur lorsqu'il interagit avec le widget
●
Pour tester la navigation, il faut créer de nouvelles pages.
– Créer un dossier screens sous lib
– Ajouter un statelessWidget dans ce dossier (Nommer par exemple
Page2) qui va afficher un Text dans un Widget Center
– importer [Link] dans le [Link]
Router
La navigation
●
Les routes nommées
●
Pour les routes nommées, elles sont définies à travers la donnée membre
routes du Widget de base Application
●
Pour chaque route, on indique la page qui doit s'afficher. La page est une
instance d'une classe dérivée de Stateless ou Stateful widget
La navigation
●
Les routes nommées sont très utiles, simples et proche d'une navigation sur
Internet
●
Pour de grands projets (beaucoup de routes, la gestion peut devenir
complexe), Les routes nommées sont moins adaptées
●
Lorsque les états des différentes pages sont complexes, l'utilisation des
routes est déconseillée. Il faut mettre en place un mécanisme de gestion de
l'état
Asynchrone
Méthode Asynchrone
●
Les méthodes asynchrones permettent d'indiquer au système qu'une
opération va être longue et qu'il peut reprendre la main pour faire d'autres
opérations.
●
Opérations longues
– Accès à la base de données locale
– Lecture de fichiers locaux (assets)
– Accès à un serveur distant
●
Flutter permet également d'afficher un widget en attendant la réponse
Future, await, async
●
L'état du widget change (no data -> data). Un statefulwidget est donc utilisé.
●
FutureBuilder prend deux arguments obligatoire
– future : une fonction asynchrone qui renseignera une variable
[Link] lorsque les données seront disponible.
– builder : le builder pourra examiner le snapshot pour savoir si les
données ont été reçues
Future, await, async
http
●
Ajoutez le package http au projet
En production, , il est nécessaire d'ajouter les permissions pour autoriser le
smartphone à accéder à Internet
– Android : Fichier android->src->main
– iOS : Les appels vers un serveur https est autorisé par défaut
Communication serveur
http
●
Utilisation de l'API : [Link]
●
Créez le modèle Album
●
Ajoutez un constructeur nommé pour Album pour la dé-sérialisation json
●
Ajoutez le gestionnaire d'état d'un statefulWidget qui affichera le json sur la
page (dans un widget Center)
●
Désérialisez le json en un objet Album
●
Affichez le title de l'album obtenu
Base de données locales
Local storage
●
Il est parfois nécessaire de stocker de données sur le smartphone
●
On peut stocker les données dans une base sharedPreferences ou SQLite
●
SharedPreferences
– Léger
– Stockage clé/valeur
●
SQLite
– Base de données relationnelle
– Moteur SQL de plusieurs Ko
Local storage
●
Les fonctionnalités de SQLite sont apportées par un package externe qu'il
faut ajouter au projet. SQLite a également besoin du package path
●
Cette commande ajoute les informations sur le package importé dans le
fichier [Link]
semver
●
La gestion sémantique des versions est un standard pour tous les langages
de développement (PHP, Typescript, Python, Flutter,...)
●
Il est nécessaire de garder une trace des versions compatibles des
packages utilisés dans un projet.
●
semver se base sur 3 chiffres qui définissent une version
– [Link]
●
Lorsqu'on publie une nouvelle version, on incrémente un des numéros de la
version
●
On incrémente le numéro de version suivant cette politique
– le numéro de version MAJEUR quand il y a des changements non
rétrocompatibles,
– le numéro de version MINEUR quand il y a des ajouts de fonctionnalités
rétrocompatibles,
– le numéro de version de CORRECTIF quand il y a des corrections
d’anomalies rétrocompatibles.
semver
●
Signification des signes
– ^ Utilisé pour indiquer une plage de versions compatibles dans la
même série de modifications (même majeure)
– >= Indique une dépendance avec une version égale ou supérieure à la
version spécifiée tout en conservant la majeure
– <= Indique une dépendance avec une version strictement inférieure à la
version spécifiée.
– < : Indique une dépendance avec une version strictement inférieure à la
version spécifiée.
– > : Indique une dépendance avec une version strictement supérieure à
la version spécifiée.
Local storage
●
On veut stocker le nom et prénom des utilisateurs qui pourront entrer ces
informations sur un formulaire (Dans une application réelle, l'application se
connecterait à un serveur distant – voir pages suivantes API)
●
Créer un dossier models dans lib
●
Créer un fichier [Link] avec la classe User permettant de stocker les
informations
●
Ajouter une méthode toMap() à User
– Mapping de la database en un objet (au sens POO)
●
Ajouter une méthode toString()
– Permet la sérialisation pour l'affichage à l'écran
Local storage
●
Modifier le fichier [Link]
Requete
N° de version de
la base
Local storage
●
Si on doit modifier le schéma de la base de données, on peut ajouter la
propriété onUpgrade()
Local storage
●
Exercice :
– Créer une table locale sqlite avec un champ firstname et lastname
– Modifier la table locale en ajoutant un champ mail
– Afficher le numéro de version de votre table
Développement en couches & CRUD
●
Créer un dossier services sous lib
●
Créer une classe DatabaseService qui va ouvrir la base de données
●
Ajouter la méthode insert() sur la classe User
●
Appeler la fonction depuis le main
●
[Link]('INSERT INTO users(firstname, lastname, mail)
VALUES($firstname, $lastname, $mail');
DANGER
INJECTION SQL
Insert
●
Pour éviter les injections SQL
●
Utiliser les requêtes paramétrées
– [Link]('INSERT INTO users(firstname, lastname, mail)
VALUES( ?, ?,?)', [firstname, lastname, mail]) ;
●
Utiliser la méthode insert de sqflite qui prend en paramètre une
Map(colonne, value) pour insérer les données
– [Link]('users', [Link]()) ;
●
insert et update prennent un argument nommé
– conflictAlgorithm valant replace ou ignore
CRUD - CREATE
Formulaires
Formulaire - Graphique
●
Il existe un grand nombre de widgets pour interagir avec l'application
– Bouton : ElevatedButton, FilledButton, IconButton, ...
– Texte : TextFormField
– Valeur numérique : Slider
– Case à cocher : Radio, Checkbox
– Date : DatePicker, TimePicker
– ...
●
Les widgets de saisie sont généralement placés dans des (dérivés de)
StatefulWidget pour gérer leur état
●
Un globalKey est ajouté pour connaitre le Widget
Formulaire - Validation
●
Validation
– Il est possible de rajouter un validateur sur les données saisies par
l'utilisateur
Formulaire – Traiter la valeur saisie
●
La valeur saisie est stockée par un TextEditingController présent dans le
gestionnaire d'état (state) du StatefulWidget
●
Instanciation et destruction du TextEditingController
Formulaire – Traiter la valeur saisie
●
On indique la méthode qui sera chargée de traiter la valeur saisie lors de
l'initialisation de l'état
●
La méthode _storeText est une méthode du gestionnaire d'état qui permet
de manipuler la valeur saisie
Variable d'environnement
Environnement
●
Les urls et autres constantes doivent se trouver dans un fichier de
configuration (.env par convention)
●
Ce fichier n'est pas versionné et est différent selon le serveur sur lequel on
travaille (développement, intégration, production)
●
Ajouter le package dotenv et placer l'url de l'API dans ce fichier.
State Management
Gestion des états
●
La gestion des états consiste à maintenir les différents widgets
affichant de l'information en adéquation avec l'état actuel de
l'application
●
Comme pour les applications web réactive, l'objectif est de
faire en sorte que seuls les éléments (les widgets) qui doivent
changer se ré-affiche sans que les autres ne soient impactés
– Cela permet à l'application d'être plus réactive
– La page entière n'a pas à être réaffichée (gain en rapidité,
fluidité, consommation ressources diminuée)
Exemples
●
Conserver et afficher les choix et
préférences de l'utilisateur
●
Montrer Les informations de choix
sur plusieurs widgets
●
...
Gestion des états
●
Pour gérer les états de l'application (state management), beaucoup d''appro
ches différentes sont disponibles
– setState() : Solution bas niveau. Fonctionne très bien lorsque l'état reste
simple à gérer
– InheritedWidget : Permet de parcourir l'arbre des widgets pour
déterminer ceux qui sont impactés
– Redux : Implémentation proche de la bibliothèque redux du framework
React
– Bloc : Business Logic Component. Proche du MVVM (Le BloC remplace
le ViewModel
– GetIt : Plugin très complet qui apporte également d'autres
fonctionnalités. Utilise le design pattern Observer<->Listener
Gestion des états
●
Avantages des solutions mises en oeuvre
– Gestion centralisée des états (moins de bugs)
– Séparation des responsabilités (SRP)
●
Inconvénients
– Apprentissage complexe au départ
– Ajout de beaucoup de fichiers (inutile pour les états simples)
– Choix large et donc difficile à déterminer celui qui correspond le mieux à
l'application en développement
setState()
●
Dans la classe héritée de State, on définit une méthode appelant setState()
●
L'appel de setState force le widget à se recréer (et se ré-afficher)
setState()
●
Avantages
– Le plus simple à mettre en place
– Suffit pour les gestions simples d'états
●
Inconvénients
– La gestion des états est intégrée dans le widget
– Compliquer à maintenir (lorsqu'il y a une gestion d'état importante)
inheritedWidget
●
InheritedWidget est un widget particulier qui va stocker les données.
Lorsqu'une données est modifiée, il informe les widgets enfants qu'une
information a été modifiée. Ils ont alors la possibilité de se redessiner
●
Cet objet dérivé de InheritedWidget contient
les données de l'état qui vont varier
●
La fonction of est un constructeur static. Il
renvoie une instance de l'objet si elle existe
déjà ou en créé une
InheritedWidget
●
L'InheritedWidget doit etre le parent du
widget stateful qui sera modifiable.
●
Généralement, on met ce widget en tête
de l'arbre
InheritedWidget – Exercice 1
●
Modifier le code afin de porter plusieurs informations. Ajouter un container
et un second BottomFloatingButton
●
Le second FloatingButton permet de changer aléatoirement la couleur du
container
●
AppData portera les informations et le code permettant de gérer/modifier :
– le compteur
– la couleur du container
InheritedWidget – Exercice 2
●
Créer une application Flutter permettant de liker des films
– La liste des films est disponible sur [Link]
●
Utiliser l'API pour afficher la liste des films actuellement à l'affiche
– L'application dispose d'une liste de films, l'affiche du film et leur titre
(voir documentation)
– Lorsque l'utilisateur clique sur la vignette d'un film, le contour change
montrant que ce film est sélectionné. (un second clic le désélectionne)
– Un compteur dans la AppBar montre le nombre de films likés
●
Lorsque l'utilisateur revient sur l'application, il retrouve tous les films qu'il a
liké (la persistance se fait en local)
InheritedWidget – Exercice 2 - Informations
●
la documentation de l'API est disponible sur l'url
– [Link]
●
Liste des films à l'affiche
– [Link]
=1
●
Images
– [Link] de l'image}/{chemin de l'affiche}
– chemin de l'affiche
○
Donner dans la réponse de la liste des pages
– taille de l'image : w92, w154, w185, w342, w500, w780, original
○
exemple :[Link]
[Link]
○
Informations - Suite
●
Pour l'authentification, deux méthodes sont possibles :
– clé api_key en paramètre de l'url (&api_key=xxxxxxxxxx)
– Bearer token. Dans les appels, on ajoute des en-têtes pour la requete)
– 'Authorization' : 'Bearer eyzzzzzzzzzzzzzzzzzzzz'
Provider
●
Le gestionnaire d'état Provider utilise le concept de notifications de
changement (Change Notification). Cela permet de notifier les widgets qui
écoutent d'un changement de l'état.
Provider
●
Design Pattern Observer
Provider
●
On indique les providers qui sont ●
On créé la classe qui gère l'état
dans l'application
Provider
●
Le widget contenant le listener
●
Appel de la méthode qui fait le changement d'état
Gestion des états
●
Le dépôt [Link] décrit
les différents gestionnaires d'état utilisés par Flutter
●
Ce dépôt montre également l'implémentation les designs d'architectures
sous Flutter (MVC, MVU,...)
Capteurs
Accès aux capteurs
●
Les smartphones modernes disposent de plusieurs capteurs
– photos/vidéos
– accéléromètre
– baromètre (capteur de pression)
– GPS
– microphone
– Capteur d'empreintes digitales
– Capteur infrarouge
– Capteur d'humidité
– ....
Permissions
●
Les permissions sont nécessaires pour que l'appareil demande à
l'utilisateur s'il accepte que l'application puisse accéder à des capteurs,
accéder aux contacts, passer des appels,...
●
Les permissions sont ajoutées dans le manifest Android
– Fichier android/app/src/main/[Link]
●
Pour l'appareil photo, on ajoute 2 permissions :
– Demande à l'utilisateur d'utiliser la caméra
– Demande d'utiliser le matériel caméra du smartphone
Utiliser la caméra
●
minSdkVersion 21 (app/[Link])
●
Ajouter le package camera
●
Ajouter les packages path et path_provider (pour stocker les photos)
●
Ne fonctionne que sur smartphone/émulateur. Accès à l'appareil photo non
assuré sur les autres devices
●
Au démarrage de l'application, on recherche le nombre et les fonctionnalités
des caméras
Sur l'état, on initialise l'accès à l'appareil photo
●
sur le clic du bouton de la bottomBar, on prend une photo
Projet
●
Invitation sur le github hébergeant l'application API en Flutter
●
Sur l'application Flutter, vous devez avoir :
– un fichier [Link] qui explique ce que fait l'application. Si des
éléments particuliers sont nécessaires pour faire fonctionner
l'application, il faut l'indiquer
– Le package dotenv doit être utilisé
●
Le code doit être commenté et correctement formaté
Projet Flutter
●
Par groupe de 3 ou 4 personnes, l'objectif est de réaliser une application
pour un entraineur qui veut suivre l'entrainement du sportif à distance.
●
Le sportif en question est un boxeur. Les exercices attendus par l'entraineur
sont
– cross (sur terrain accidenté et sans connectivité mobile assurée)
– saut à la corde
●
Les entrainements sont journalisés. Il y a donc des données stockées par
journée d'entrainement
●
Projet Flutter
●
L'entraineur veut pouvoir avoir aux fonctionnalités suivantes
– Voir les parcours effectués par le sportif sur une carte
– Savoir le nombre de sauts effectués par le sportif pendant les séances
de saut à la corde
Projet Flutter
●
mettre le projet sur git et inviter l'utilisateur smartmoov
– Le [Link] contient les membres du groupe et toutes les
indications permettant de lancer le projet
●
Proposez des wireframes et maquettes à l'entraineur avant de démarrer le
développement
●
Développer d'abord une des fonctionnalités (suivi des saut/parcours cross)
– L'objectif est d'avoir un code propre et lisible
●
On se limitera à l'application du sportif
●
L'envoi des données collectées par l'application mobile vers un back-end ne
sera pas fait. Le format des données sera toutefois commenté et expliqué.
Projet Flutter
●
Note
– On fera l'application dédiée au sportif et non à l'entraineur
– Dans une application réelle, les données seront remontées vers un
serveur distant.