Flutter Tutorial
Flutter Tutorial
je
Machine Translated by Google
À propos du tutoriel
Flutter est un framework open source permettant de créer des applications mobiles de haute qualité et de haute performance
sur les systèmes d'exploitation mobiles Android et iOS. Il fournit un SDK simple, puissant, efficace et facile à comprendre
pour écrire des applications mobiles dans le langage de Google, Dart.
Ce didacticiel présente les bases du framework Flutter, l'installation du SDK Flutter, la configuration d'Android Studio pour
développer une application basée sur Flutter, l'architecture de Flutter
framework et développement de tous types d'applications mobiles en utilisant le framework Flutter.
Public
Ce tutoriel est destiné aux professionnels qui souhaitent faire carrière dans le domaine des applications mobiles. Ce tutoriel
a pour but de vous familiariser avec le framework Flutter et ses différentes fonctionnalités.
Prérequis
Ce tutoriel est écrit en supposant que les lecteurs savent déjà ce qu'est un Framework et qu'ils ont une solide connaissance
de la programmation orientée objet et des connaissances de base sur le framework Android et la programmation Dart.
Si vous êtes débutant dans l’un de ces concepts, nous vous suggérons de suivre d’abord des tutoriels liés à ceuxci, avant
de commencer avec Flutter.
Tout le contenu et les graphiques publiés dans cet ebook sont la propriété de Tutorials Point (I)
Il est interdit à l'utilisateur de ce livre électronique de réutiliser, conserver, copier, distribuer ou republier tout contenu ou
une partie du contenu de ce livre électronique de quelque manière que ce soit sans le consentement écrit de l'éditeur.
Nous nous efforçons de mettre à jour le contenu de notre site Web et de nos tutoriels aussi rapidement et aussi précisément
que possible. Cependant, le contenu peut contenir des inexactitudes ou des erreurs. Tutorials Point (I) Pvt.
Ltd. ne fournit aucune garantie concernant l'exactitude, l'actualité ou l'exhaustivité de notre site Web
ou de son contenu, y compris ce tutoriel. Si vous découvrez des erreurs sur notre site Web ou dans ce
tutoriel, veuillez nous en informer à l'adresse contact@tutorialspoint.com
je
Machine Translated by Google
Battement
Public................................................................................................................................................i
Prérequis................................................................................................................................................i
Fonctionnalités de Flutter.................................................................................................................................1
Inconvénients de Flutter..................................................................................................................................2
Widgets ................................................................................................................................................12
Gestes ................................................................................................................................................................13
Couches................................................................................................................................................13
Fonctions................................................................................................................................................16
je
Machine Translated by Google
Battement
Introduction................................................................................................................................................82
Types de forfaits................................................................................................................................103
Concepts de base................................................................................................................................114
iii
Machine Translated by Google
Battement
SQLite ..........................................................................................................................................................125
Types de tests.................................................................................................................................................147
Exemple de travail................................................................................................................................149
Application Android................................................................................................................................151
iv
Machine Translated by Google
1. Flutter – Présentation
En général, développer une application mobile est une tâche complexe et difficile. Il existe de nombreux
frameworks disponibles pour développer une application mobile. Android fournit un framework natif basé sur le
langage Java et iOS fournit un framework natif basé sur le langage ObjectiveC / Shift.
Cependant, pour développer une application prenant en charge les deux systèmes d'exploitation, nous devons
coder dans deux langages différents en utilisant deux frameworks différents. Pour surmonter cette complexité, il
existe des frameworks mobiles prenant en charge les deux systèmes d'exploitation. Ces frameworks vont du
simple framework d'application mobile hybride basé sur HTML (qui utilise HTML pour l'interface utilisateur et
JavaScript pour la logique d'application) au framework complexe spécifique à un langage (qui se charge de la
conversion du code en code natif). Quelle que soit leur simplicité ou leur complexité, ces frameworks présentent
toujours de nombreux inconvénients, l'un des principaux étant leur lenteur.
Dans ce scénario, Flutter, un framework simple et performant basé sur le langage Dart, offre des performances
élevées en rendant l'interface utilisateur directement dans le canevas du système d'exploitation plutôt que via un
framework natif.
Flutter propose également de nombreux widgets prêts à l'emploi (UI) pour créer une application moderne.
les widgets sont optimisés pour l'environnement mobile et la conception de l'application à l'aide de widgets est
aussi simple que la conception HTML.
Pour être plus précis, l'application Flutter est ellemême un widget. Les widgets Flutter prennent également en
charge les animations et les gestes. La logique de l'application est basée sur la programmation réactive. Le widget
peut éventuellement avoir un état. En modifiant l'état du widget, Flutter comparera automatiquement (programmation
réactive) l'état du widget (ancien et nouveau) et restituera le widget avec uniquement les modifications nécessaires
au lieu de restituer l'ensemble du widget.
Fonctionnalités de Flutter
1
Machine Translated by Google
Battement
Avantages de Flutter
Flutter est livré avec de magnifiques widgets personnalisables pour des performances élevées et une
application mobile exceptionnelle. Il répond à tous les besoins et exigences personnalisés. Outre ceux
ci, Flutter offre de nombreux autres avantages, comme mentionné cidessous :
• Dart dispose d'un vaste référentiel de packages logiciels qui vous permettent d'étendre les
capacités de votre application.
• Les développeurs doivent écrire une seule base de code pour les deux applications (plateformes
Android et iOS). Flutter pourrait également être étendu à d'autres plateformes à l'avenir.
• Flutter nécessite moins de tests. En raison de sa base de code unique, il suffit d'écrire des tests
automatisés une fois pour les deux plateformes.
• La simplicité de Flutter en fait un bon candidat pour un développement rapide. Sa capacité de
personnalisation et son extensibilité le rendent encore plus puissant.
• Avec Flutter, les développeurs ont un contrôle total sur les widgets et leur disposition.
• Flutter propose d'excellents outils de développement, avec un rechargement à chaud incroyable.
Inconvénients de Flutter
Malgré ses nombreux avantages, Flutter présente les inconvénients suivants :
• Comme il est codé en langage Dart, un développeur doit apprendre un nouveau langage (bien qu'il
soit facile à apprendre).
• Les frameworks modernes tentent de séparer autant que possible la logique et l'interface utilisateur, mais dans Flutter,
l'interface utilisateur et la logique sont mélangées. Nous pouvons surmonter ce problème en utilisant un codage
intelligent et en utilisant un module de haut niveau pour séparer l'interface utilisateur et la logique.
• Flutter est un autre framework pour créer des applications mobiles. Les développeurs ont du mal
à choisir les bons outils de développement dans un segment de plus en plus peuplé.
2
Machine Translated by Google
Ce chapitre vous guidera en détail tout au long de l'installation de Flutter sur votre ordinateur local.
Étape 3 : mettez à jour le chemin d’accès système pour inclure le répertoire bin de Flutter.
Étape 4 : Flutter fournit un outil, Flutter Doctor, pour vérifier que toutes les exigences de développement de Flutter sont satisfaites.
docteur flutter
Étape 5 : L’exécution de la commande cidessus analysera le système et affichera son rapport comme indiqué cidessous :
Résumé du docteur (pour voir tous les détails, exécutez flutter doctor v) :
[√] Flutter (Canal stable, v1.2.1, sur Microsoft Windows [Version 10.0.17134.706], locale enUS)
[√] Chaîne d'outils Android développement pour les appareils Android (version Android SDK 28.0.3)
Le rapport indique que tous les outils de développement sont disponibles mais que l'appareil n'est pas connecté.
Nous pouvons résoudre ce problème en connectant un appareil Android via USB ou en démarrant un émulateur Android.
Étape 9 : Installez le plugin Flutter et Dart pour Android Studio. Il fournit un modèle de démarrage pour créer une nouvelle application
Flutter, une option pour exécuter et déboguer l'application Flutter dans le studio Android luimême, etc.
3
Machine Translated by Google
Battement
Pour installer Flutter sur MacOS, vous devrez suivre les étapes suivantes :
Étape 3 : mettez à jour le chemin d’accès système pour inclure le répertoire bin de Flutter (dans le fichier ~/.bashrc).
Étape 4 : activez le chemin mis à jour dans la session en cours à l’aide de la commande cidessous, puis vérifiezle
également.
source ~/.bashrc
source $HOME/.bash_profile écho
$PATH
Flutter fournit un outil, Flutter Doctor, pour vérifier que toutes les exigences de développement de Flutter sont
respectées. Il est similaire à son homologue Windows.
Étape 5 : Installez la dernière version de XCode, si elle est signalée par Flutter Doctor
Étape 8 : Démarrez un émulateur Android ou connectez un véritable appareil Android au système pour développer une
application Android.
Étape 9 : ouvrez le simulateur iOS ou connectez un véritable appareil iPhone au système pour développer une
application iOS.
Étape 10 : Installez le plugin Flutter et Dart pour Android Studio. Il fournit le modèle de démarrage pour créer une
nouvelle application Flutter, l'option d'exécuter et de déboguer l'application Flutter dans le studio Android luimême, etc.
4
Machine Translated by Google
Android Studio
Dans ce chapitre, créons une application Flutter simple pour comprendre les bases de la création d'une application
Flutter dans Android Studio.
Étape 2 : Créer un projet Flutter. Pour cela, cliquez sur Fichier > Nouveau > Nouveau projet Flutter
5
Machine Translated by Google
Battement
Étape 3 : Sélectionnez l'application Flutter. Pour cela, sélectionnez l'application Flutter et cliquez sur Suivant.
6
Machine Translated by Google
Battement
Android Studio crée une application Flutter entièrement fonctionnelle avec des fonctionnalités minimales.
Vérifions la structure de l’application, puis modifions le code pour effectuer notre tâche.
7
Machine Translated by Google
Battement
• Android Code source généré automatiquement pour créer une application Android
• ios Code source généré automatiquement pour créer une application ios
• lib Dossier principal contenant le code Dart écrit à l'aide du framework Flutter
8
Machine Translated by Google
Battement
Étape 7 : remplacez le code dart dans le fichier lib/main.dart par le code cidessous :
importer 'package:flutter/material.dart';
build(BuildContext context) {
renvoie MaterialApp(
titre : « Application de démonstration Hello World »,
thème :
ThemeData( primarySwatch :
@override
Widget build(BuildContext context) { return Scaffold( appBar:
AppBar( title:
Texte(this.title), ), corps:
Centre( enfant: Texte( 'Bonjour le
monde',
), );
}
}
• Ligne 1 : importe le package Flutter, material. Material est un package Flutter permettant de créer une
interface utilisateur conformément aux directives de conception Material spécifiées par Android.
• Ligne 3 : il s'agit du point d'entrée de l'application Flutter. Appelle la fonction runApp et lui transmet un
objet de la classe MyApp . Le but de la fonction runApp est d'attacher le widget donné à l'écran.
• Ligne 5 17 : Widget est utilisé pour créer une interface utilisateur dans le framework Flutter. StatelessWidget
est un widget qui ne conserve aucun état du widget. MyApp étend StatelessWidget et remplace sa
méthode de construction . Le but de la construction
9
Machine Translated by Google
Battement
La méthode build consiste à créer une partie de l'interface utilisateur de l'application. Ici, la méthode build
utilise MaterialApp, un widget pour créer l'interface utilisateur de niveau racine de l'application. Elle possède
trois propriétés : titre, thème et accueil.
o theme est le thème du widget. Ici, nous définissons le bleu comme couleur générale de l'application
en utilisant la classe ThemeData et sa propriété, primarySwatch.
o home est l'interface utilisateur interne de l'application, dans laquelle nous définissons un autre widget,
Ma page d'accueil
écran.
10
Machine Translated by Google
Battement
11
Machine Translated by Google
Widgets
Le concept de base du framework Flutter est le suivant : dans Flutter, tout est un widget. Les widgets sont
essentiellement des composants d'interface utilisateur utilisés pour créer l'interface utilisateur de l'application.
Dans Flutter, l'application ellemême est un widget. L'application est le widget de niveau supérieur et son interface
utilisateur est construite à l'aide d'un ou plusieurs enfants (widgets), qui sont euxmêmes construits à l'aide de leurs
widgets enfants. Cette fonctionnalité de composabilité nous aide à créer une interface utilisateur de toute complexité.
Par exemple, la hiérarchie des widgets de l'application hello world (créée dans le chapitre précédent) est telle que
spécifiée dans le diagramme suivant :
12
Machine Translated by Google
Battement
• MyApp est le widget créé par l'utilisateur et il est construit à l'aide du widget natif Flutter,
Application matérielle.
• MaterialApp possède une propriété home pour spécifier l'interface utilisateur de la page d'accueil,
qui est encore un widget créé par l'utilisateur, MyHomePage.
• MyHomePage est construit à l'aide d'un autre widget natif Flutter, Scaffold.
• body est utilisé pour spécifier son interface utilisateur principale et appBar est utilisé pour spécifier son entête
interface utilisateur.
• L'interface utilisateur d'entête est créée à l'aide du widget natif Flutter, l'interface utilisateur AppBar et Body est créée à l'aide
Widget central .
• Le widget Centre possède une propriété, Enfant, qui fait référence au contenu réel et il est construit à l'aide du widget Texte .
Gestes
Les widgets Flutter prennent en charge l'interaction via un widget spécial, GestureDetector.
GestureDetector est un widget invisible ayant la capacité de capturer les interactions de l'utilisateur telles que le tapotement,
le glissement, etc., de son widget enfant. De nombreux widgets natifs de Flutter prennent en charge l'interaction via l'utilisation
de GestureDetector. Nous pouvons également incorporer une fonctionnalité interactive dans le widget existant en le composant
avec le widget GestureDetector . Nous apprendrons les gestes séparément dans les prochains chapitres.
Notion d'État
Les widgets Flutter prennent en charge la maintenance de l'état en fournissant un widget spécial, StatefulWidget.
Le widget doit être dérivé du widget StatefulWidget pour prendre en charge la maintenance de l'état et tous les autres widgets
doivent être dérivés de StatelessWidget. Les widgets Flutter sont réactifs en natif. Ceci est similaire à reactjs et StatefulWidget
sera automatiquement réaffiché chaque fois que son état interne est modifié. Le réaffichage est optimisé en trouvant la
différence entre l'ancienne et la nouvelle interface utilisateur du widget et en affichant uniquement les modifications nécessaires.
Couches
Le concept le plus important du framework Flutter est que le framework est regroupé en plusieurs catégories en termes de
complexité et clairement organisé en couches de complexité décroissante. Une couche est construite en utilisant sa couche
de niveau immédiatement suivant. La couche la plus haute est un widget spécifique à Android et iOS. La couche suivante
contient tous les widgets natifs de Flutter. La couche suivante est la couche de rendu , qui est un composant de rendu de bas
niveau et restitue tout dans l'application Flutter. Les couches descendent jusqu'au code spécifique à la plateforme principale.
13
Machine Translated by Google
Battement
L'aperçu général d'une couche dans Flutter est spécifié dans le diagramme cidessous :
• Des fonctionnalités interactives peuvent être intégrées chaque fois que nécessaire à l'aide de GestureDetector
widget.
• L'état d'un widget peut être maintenu chaque fois que nécessaire à l'aide de StatefulWidget
widget.
• Flutter propose une conception en couches afin que n'importe quelle couche puisse être programmée en fonction
de la complexité de la tâche.
Nous discuterons de tous ces concepts en détail dans les prochains chapitres.
14
Machine Translated by Google
Dart est un langage de programmation open source à usage général. Il a été développé à l'origine par Google. Dart est un
langage orienté objet avec une syntaxe de style C. Il prend en charge des concepts de programmation tels que les interfaces
et les classes, contrairement à d'autres langages de programmation, Dart ne prend pas en charge les tableaux. Les
collections Dart peuvent être utilisées pour répliquer des structures de données telles que des tableaux, des génériques et
un typage facultatif.
void main()
{
print("Le langage Dart est facile à apprendre");
}
Dart utilise le motclé var pour déclarer la variable. La syntaxe de var est définie cidessous,
Les motsclés final et const sont utilisés pour déclarer des constantes. Elles sont définies comme suit :
• Nombres : ils sont utilisés pour représenter des littéraux numériques – Entier et Double.
• Chaînes : elles représentent une séquence de caractères. Les valeurs de chaîne sont spécifiées entre guillemets simples
ou doubles.
• Booléens : Dart utilise le motclé bool pour représenter les valeurs booléennes : true et false.
• Listes et cartes : elles sont utilisées pour représenter une collection d'objets. Une liste simple peut être définie comme
suit :
15
Machine Translated by Google
Battement
• Dynamique : Si le type de variable n'est pas défini, son type par défaut est dynamique .
L'exemple suivant illustre la variable de type dynamique :
Les boucles sont utilisées pour répéter un bloc de code jusqu'à ce qu'une condition spécifique soit remplie. Dart prend en
, Boucles while et do..while.
charge for, for..in
Voyons un exemple simple sur l’utilisation des instructions de contrôle et des boucles :
void main()
{ pour( var i = 1 ; i <= 10; i++ ) { si(i%2==0)
{
imprimer(i);
}
}
}
Fonctions
Une fonction est un groupe d'instructions qui, ensemble, exécutent une tâche spécifique. Examinons
une fonction simple dans Dart comme illustré ici :
void main()
{ ajouter(3,4);
}
c=a+b;
imprimer(c);
}
16
Machine Translated by Google
Battement
Une classe est un plan directeur pour la création d'objets. Une définition de classe comprend les éléments suivants :
• Champs
• Getters et setters
• Constructeurs
• Fonctions
classe Employé {
Nom de la chaîne ;
//méthode getter
Chaîne obtenir emp_name
{ renvoyer le nom ;
}
//méthode setter
void set emp_name(Chaîne nom)
{ this.name = nom;
}
//définition de fonction
résultat nul()
{
imprimer(nom);
}
} void main() { //
création d'objet
Employé emp = nouvel employé();
emp.name="employee1";
emp.result(); //appel de fonction
}
17
Machine Translated by Google
Comme nous l'avons appris dans le chapitre précédent, les widgets sont essentiels dans le framework Flutter. Nous
avons déjà appris à créer de nouveaux widgets dans les chapitres précédents.
Dans ce chapitre, comprenons le concept réel derrière la création des widgets et les différents types de widgets
disponibles dans le framework Flutter .
Voyons maintenant le widget MyHomePage de l'application Hello World . Le code utilisé à cet effet est le suivant :
@outrepasser
Création de widget (contexte BuildContext) {
retourner l'échafaudage(
Barre d'application : Barre d'application (
titre : Texte(this.title),
),
corps : Centre(
enfant: Texte(
'Bonjour le monde',
)),
);
}
}
Notez que le StatelessWidget ne nécessite qu'une seule méthode build pour être implémenté dans sa classe dérivée.
La méthode build obtient l'environnement de contexte nécessaire pour construire les widgets via le paramètre
BuildContext et renvoie le widget qu'elle construit.
Dans le code, nous avons utilisé le titre comme l'un des arguments du constructeur et également la clé comme autre
argument. Le titre est utilisé pour afficher le titre et la clé est utilisée pour identifier le widget dans l'environnement de
construction.
Ici, la méthode build appelle la méthode build de Scaffold, qui à son tour appelle la méthode build
méthode de AppBar et Center pour construire son interface utilisateur.
18
Machine Translated by Google
Battement
Pour une meilleure compréhension, la représentation visuelle de celleci est donnée cidessous :
Dans Flutter, les widgets peuvent être regroupés en plusieurs catégories en fonction de leurs fonctionnalités, comme indiqué ci
dessous :
Les widgets spécifiques à Android sont conçus conformément aux directives de conception Material du système d'exploitation
Android. Les widgets spécifiques à Android sont appelés widgets Material.
Les widgets spécifiques à iOS sont conçus conformément aux directives d'interface humaine d'Apple et sont appelés widgets
Cupertino .
Certains des widgets matériels les plus utilisés sont les suivants :
• Échafaudage
• Barre d'applications
19
Machine Translated by Google
Battement
• TabBarView
• ListeTile
• Bouton en relief
• Bouton d'icône
• Bouton déroulant
• Champ de texte
• Case à cocher
• Radio
• Interrupteur
• Curseur
• SimpleDialog •
AlertDialog
Certains des widgets les plus utilisés de Cupertino sont les suivants :
• Bouton Cupertino
• Cueilleur de Cupertino
• CupertinoDatePicker •
CupertinoTimerPicker
• CupertinoTabScaffold •
CupertinoTabView •
CupertinoTextField
• CupertinoDialog
• CupertinoDialogAction
• CupertinoFullscreenDialogTransition •
CupertinoPageScaffold
• CupertinoPageTransition
• CupertinoActivityIndicator •
CupertinoAlertDialog •
CupertinoPopupSurface
20
Machine Translated by Google
Battement
• Curseur de Cupertino
Dans Flutter, un widget peut être créé en composant un ou plusieurs widgets. Pour composer plusieurs widgets en un seul
widget, Flutter fournit un grand nombre de widgets avec une fonction de mise en page. Par exemple, le widget enfant peut
être centré à l'aide du widget Centrer .
Certains des widgets de mise en page les plus populaires sont les suivants :
Nous vérifierons les widgets de mise en page en détail dans la prochaine Introduction aux widgets de mise en page
chapitre.
Le widget dérivé de StatelessWidget ne contient aucune information d'état, mais il peut contenir un widget dérivé de
StatefulWidget. La nature dynamique de l'application repose sur le comportement interactif des widgets et les changements
d'état au cours de l'interaction. Par exemple, appuyer sur un bouton de compteur augmentera/diminuera l'état interne du
compteur d'un point et la nature réactive du widget Flutter rendra automatiquement le widget à l'aide de nouvelles informations
d'état.
Nous apprendrons le concept des widgets StatefulWidget en détail dans le prochain chapitre sur la gestion des états .
Flutter propose un grand nombre de widgets de base pour créer des interfaces utilisateur simples ou complexes de manière
indépendante de la plateforme. Voyons quelquesuns des widgets de base dans ce chapitre.
Texte
Le widget de texte est utilisé pour afficher un morceau de chaîne. Le style de la chaîne peut être défini à l'aide de la propriété
style et de la classe TextStyle . L'exemple de code à cet effet est le suivant :
Le widget de texte possède un constructeur spécial, Text.rich, qui accepte l'enfant de type TextSpan
pour spécifier la chaîne avec un style différent. Le widget TextSpan est récursif par nature et accepte TextSpan comme ses
enfants. L'exemple de code à cet effet est le suivant :
21
Machine Translated by Google
Battement
Les propriétés les plus importantes du widget Texte sont les suivantes :
• textAlign, TextAlign : alignement du texte comme à droite, à gauche, justifier, etc., en utilisant
Classe TextAlign
• textDirection, TextDirection : direction du texte à faire circuler, soit de gauche à droite, soit de droite à gauche.
à gauche
Image
Le widget Image est utilisé pour afficher une image dans l'application. Le widget Image fournit différents constructeurs
pour charger des images à partir de plusieurs sources et ils sont les suivants :
L'option la plus simple pour charger et afficher une image dans Flutter consiste à inclure l'image en tant qu'actif de
l'application et à la charger dans le widget à la demande.
• Créez un dossier, assets dans le dossier du projet et placez les images nécessaires.
battement:
actifs:
assets/smiley.png
Image.asset('assets/smiley.png')
22
Machine Translated by Google
Battement
@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar( title:
Texte(this.title), ), corps:
Centre( enfant:
Image.asset("assets/smiley.png")
), );
}
23
Machine Translated by Google
Battement
Les propriétés les plus importantes du widget Image sont les suivantes :
Icône
Le widget d'icône est utilisé pour afficher un glyphe d'une police décrite dans la classe IconData . Le code pour charger
une icône de courrier électronique simple est le suivant :
Icône (Icons.email)
Le code source complet pour l'appliquer dans l'application Hello World est le suivant :
@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar( title:
Texte(this.title), ), corps:
Centre( enfant:
Icône(Icons.email)
), );
}
}
24
Machine Translated by Google
Battement
25
Machine Translated by Google
Le concept de base de Flutter étant que « tout est un widget », Flutter intègre une fonctionnalité de mise en page
de l'interface utilisateur dans les widgets euxmêmes. Flutter fournit de nombreux widgets spécialement conçus
comme Container, Center, Align, etc., uniquement dans le but de mettre en page l'interface utilisateur. Les widgets
créés en composant d'autres widgets utilisent normalement des widgets de mise en page. Apprenons le concept
de mise en page de Flutter dans ce chapitre.
Les widgets de mise en page peuvent être regroupés en deux catégories distinctes en fonction de leur enfant :
Apprenons les deux types de widgets et leurs fonctionnalités dans les sections suivantes.
Dans cette catégorie, les widgets n'auront qu'un seul widget comme enfant et chaque widget aura une fonctionnalité
de mise en page spéciale.
Par exemple, le widget Centre centre simplement son widget enfant par rapport à son widget parent et le widget
Conteneur offre une flexibilité totale pour placer son enfant à n'importe quel endroit donné à l'intérieur de celuici
en utilisant différentes options comme le remplissage, la décoration, etc.
Les widgets enfant uniques sont d'excellentes options pour créer des widgets de haute qualité ayant une
fonctionnalité unique telle qu'un bouton, une étiquette, etc.
Le code pour créer un bouton simple à l'aide du widget Container est le suivant :
@outrepasser
Création de widget (contexte BuildContext) {
renvoie le conteneur(
décoration : const BoxDecoration(
bordure : bordure(
haut : BorderSide(largeur : 1,0, couleur : Couleur(0xFFFFFFFFFF)),
gauche : BorderSide(largeur : 1,0, couleur : Color(0xFFFFFFFFFF)),
droite : BorderSide(largeur : 1,0, couleur : Color(0xFFFF000000)),
bas : BorderSide(largeur : 1,0, couleur : Color(0xFFFF000000)),
),
),
enfant : Conteneur(
rembourrage : const EdgeInsets.symmetric(horizontal : 20,0, vertical : 2,0),
décoration : const BoxDecoration(
bordure : bordure(
haut : BorderSide(largeur : 1,0, couleur : Couleur(0xFFFFDFDFDF)),
26
Machine Translated by Google
Battement
Ici, nous avons utilisé deux widgets : un widget conteneur et un widget texte . Le résultat du widget est un bouton personnalisé
comme indiqué cidessous :
Voyons quelquesuns des widgets de mise en page enfant unique les plus importants fournis par Flutter :
• Rembourrage : utilisé pour organiser son widget enfant selon le remplissage donné. Ici, le remplissage peut être fourni par
la classe EdgeInsets .
• Aligner : aligne son widget enfant sur luimême à l'aide de la valeur de la propriété d'alignement . La valeur de la propriété
d'alignement peut être fournie par la classe FractionalOffset . La classe FractionalOffset spécifie les décalages en
termes de distance à partir du coin supérieur gauche.
Centre(
enfant : Conteneur(
hauteur: 100,0,
largeur: 100,0,
couleur : Couleurs.jaune,
enfant : Align(
alignement : FractionalOffset(0.2, 0.6),
enfant : Conteneur(
hauteur: 40,0,
largeur: 40,0,
couleur : Couleurs.rouge,
),
),
),
)
• FittedBox : il met à l'échelle le widget enfant, puis le positionne en fonction de l'ajustement spécifié.
27
Machine Translated by Google
Battement
• Boîte contrainte
• Ligne de base
• Hauteur intrinsèque
• Largeur intrinsèque
• Boîte limitée
• En coulisses
• Boîte de débordement
• Boîte de taille
• Transformer
Notre application Hello World utilise des widgets de mise en page basés sur des matériaux pour concevoir la page
d'accueil. Modifions notre application Hello World pour créer la page d'accueil à l'aide de widgets de mise en page de
base comme indiqué cidessous :
• Conteneur : widget de conteneur générique, enfant unique, basé sur une boîte avec alignement, remplissage,
bordure et marge ainsi que de riches fonctionnalités de style.
• Centre : widget conteneur enfant simple et unique, qui centre son widget enfant.
@outrepasser
@outrepasser
renvoie le conteneur(
décoration : BoxDecoration(
28
Machine Translated by Google
Battement
couleur : Couleurs.blanc,
),
rembourrage : EdgeInsets.all(25),
enfant : Centre(enfant :
Texte(
'Bonjour le monde',
style:TextStyle(
couleur : Colors.noir,
),
textDirection:TextDirection.ltr,
),
));
}
}
Ici,
• Le widget conteneur est le widget de niveau supérieur ou racine. Le conteneur est configuré à l'aide des
propriétés de décoration et de remplissage pour organiser son contenu.
• BoxDecoration possède de nombreuses propriétés telles que la couleur, la bordure, etc., pour décorer le conteneur
widget et ici, la couleur est utilisée pour définir la couleur du conteneur.
• Le remplissage du widget Conteneur est défini à l'aide de la classe dgeInsets , qui fournit la possibilité de
spécifier la valeur de remplissage.
• Center est le widget enfant du widget Container . Encore une fois, Text est l'enfant du widget Center .
Text est utilisé pour afficher le message et Center est utilisé pour centrer le message texte par rapport
au widget parent, Container.
29
Machine Translated by Google
Battement
Le résultat final du code donné cidessus est un exemple de mise en page comme indiqué cidessous :
Dans cette catégorie, un widget donné aura plus d'un widget enfant et la disposition de chaque widget est unique.
Par exemple, le widget Row permet de disposer ses enfants dans le sens horizontal, tandis que le widget Column permet
de disposer ses enfants dans le sens vertical. En composant Row et Column, il est possible de créer des widgets de
n'importe quel niveau de complexité.
• Étendu Utilisé pour que les enfants du widget Ligne et Colonne occupent la
surface maximale possible.
30
Machine Translated by Google
Battement
importer 'package:flutter/material.dart';
build(BuildContext context) {
return MaterialApp( title:
'Flutter Demo', theme:
ThemeData( primarySwatch:
@outrepasser
Création de widget (contexte de construction)
{ return Scaffold(
appBar : AppBar( titre :
Texte(this.title), ), corps : Centre( enfant :
Texte(
'Bonjour le
monde', )),
);
}
}
31
Machine Translated by Google
Battement
• Ici,
• Créez maintenant un nouveau widget, ProductBox, selon la conception spécifiée comme indiqué
cidessous:
Expanded( enfant :
Container( padding :
EdgeInsets.all(5),
enfant : Column( mainAxisAlignment :
]))); }
}
32
Machine Translated by Google
Battement
o Élargi
o Rangée
o Colonne
o Carte
o Texte
l'image
33
Machine Translated by Google
Battement
• ProductBox est conçu à l'aide du widget mentionné cidessus. La disposition ou la hiérarchie du widget est
spécifiée dans le diagramme cidessous :
• Maintenant, placez une image factice (voir cidessous) pour les informations sur le produit dans le dossier assets de
l'application et configurez le dossier assets dans le fichier pubspec.yaml comme indiqué cidessous :
actifs:
assets/appimages/floppy.png assets/
appimages/iphone.png assets/appimages/
laptop.png assets/appimages/pendrive.png
assets/appimages/pixel.png assets/
appimages/tablet.png
iPhone.png
34
Machine Translated by Google
Battement
Pixel.png
Ordinateur portable.png
Tablette.png
Clé USB.png
Disquette.png
• Enfin, utilisez le widget ProductBox dans le widget MyHomePage comme indiqué cidessous :
@outrepasser
Création de widget (contexte de BuildContext)
{ return Scaffold
(appBar : AppBar (titre : Texte (« Liste des produits »)), body :
ListView
(shrinkWrap : true,
35
Machine Translated by Google
Battement
ProductBox( nom :
« Pixel », description : « Pixel est le téléphone le plus riche en
fonctionnalités »,
prix : 800, image :
« pixel.png »),
ProductBox( nom :
« Ordinateur portable », description : « L'ordinateur portable est l'outil de
développement
le plus productif », prix : 2000, image : « ordinateur portable.png »),
ProductBox( nom :
« Tablette », description : « La tablette est l'appareil le plus utile jamais conçu pour
réunion",
prix : 1500,
image : "tablet.png"),
ProductBox( nom :
« Pendrive », description : « Pendrive est un support de stockage
utile », prix :
100, image : « pendrive.png »),
ProductBox(
nom : « Lecteur de
disquette », description : « Le lecteur de disquette est un support de stockage de
secours
utile », prix : 20, image : « floppy.png »),
], ));
}
}
importer 'package:flutter/material.dart';
build(BuildContext context) {
renvoie MaterialApp( titre :
« Démo Flutter », thème :
36
Machine Translated by Google
Battement
),
home: MyHomePage(title: 'Page d'accueil de démonstration de la présentation du
produit'), );
}
}
@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar(title: Text("Product Listing")), body: ListView( shrinkWrap:
true, padding: const
EdgeInsets.fromLTRB(2.0,
10.0, 2.0, 10.0), children: <Widget>[ ProductBox( name: "iPhone", description:
"iPhone est le téléphone
le plus stylé
de tous les temps",
prix: 1000, image: "iphone.png"),
ProductBox( nom :
« Pixel », description : « Pixel est le téléphone le plus riche en
fonctionnalités »,
prix : 800, image :
« pixel.png »),
ProductBox( nom :
« Ordinateur portable », description : « L'ordinateur portable est l'outil de
développement
le plus productif », prix : 2000, image : « ordinateur portable.png »),
ProductBox( nom :
« Tablette », description : « La tablette est l'appareil le plus utile jamais conçu pour
réunion",
prix : 1500,
image : "tablet.png"),
ProductBox( nom :
« Pendrive », description : « Pendrive est un support de stockage
utile », prix :
100, image : « pendrive.png »),
ProductBox(
nom : « Lecteur de
disquette », description : « Le lecteur de disquette est un support de stockage de
secours
utile », prix : 20, image : « floppy.png »),
], ));
}
}
37
Machine Translated by Google
Battement
Container( padding :
EdgeInsets.all(5), enfant :
])));
}
}
38
Machine Translated by Google
Battement
39
Machine Translated by Google
Les gestes sont avant tout un moyen pour un utilisateur d'interagir avec une application mobile (ou tout autre appareil
tactile). Les gestes sont généralement définis comme toute action/mouvement physique d'un utilisateur dans le but
d'activer une commande spécifique de l'appareil mobile. Les gestes peuvent être aussi simples que de toucher l'écran
de l'appareil mobile ou des actions plus complexes utilisées dans les applications de jeu.
• Tap : toucher la surface de l'appareil avec le bout du doigt pendant une courte période, puis
relâcher le bout du doigt.
• Glisser : toucher la surface de l'appareil avec le bout du doigt, puis déplacer le bout du doigt de manière
régulière, puis relâcher enfin le bout du doigt.
• Panoramique : toucher la surface de l'appareil avec le bout du doigt et le déplacer dans n'importe quelle
direction sans relâcher le bout du doigt.
Flutter fournit un excellent support pour tous les types de gestes grâce à son widget exclusif, GestureDetector.
GestureDetector est un widget non visuel principalement utilisé pour détecter le geste de l'utilisateur. Pour identifier
un geste ciblé sur un widget, le widget peut être placé à l'intérieur du widget GestureDetector. GestureDetector
capturera le geste et enverra plusieurs événements en fonction du geste.
• Appuyez sur
ou surTapDown
ou surTapUp
ou surTap
ou onTapCancel
ou surDoubleTap
• Appui long
ou surLongPress
40
Machine Translated by Google
Battement
• Traînée verticale
o surVerticalDragStart
o surVerticalDragUpdate
ou surVerticalDragEnd
• Traînée horizontale
o surHorizontalDragStart
o surHorizontalDragUpdate
o surHorizontalDragEnd
• Poêle
ou surPanStart
ou surPanUpdate
ou surPanEnd
Maintenant, modifions l’application Hello World pour inclure la fonction de détection de gestes et essayons de comprendre
le concept.
corps :
Centre( enfant :
• Implémentez la fonction *_showDialog* pour présenter une boîte de dialogue lorsque l'utilisateur clique sur le
message Hello World . Elle utilise le widget générique showDialog et AlertDialog pour créer un nouveau
widget de boîte de dialogue. Le code est présenté cidessous :
41
Machine Translated by Google
Battement
• L'application se rechargera sur l'appareil à l'aide de la fonction Hot Reload . Cliquez maintenant simplement sur le message
Hello World et la boîte de dialogue cidessous s'affichera :
• Fermez maintenant la boîte de dialogue en cliquant sur l’ option Fermer dans la boîte de dialogue.
42
Machine Translated by Google
Battement
importer 'package:flutter/material.dart';
renvoie MaterialApp(
titre : « Application de démonstration Hello World »,
thème :
ThemeData( primarySwatch :
Navigateur.de(contexte).pop(); }, ), ], ); }, );
@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar( title:
Texte(this.title), ),
43
Machine Translated by Google
Battement
corps :
Centre( enfant :
GestureDetector( onTap : ()
);
}
}
Enfin, Flutter fournit également un mécanisme de détection de gestes de bas niveau via le widget Listener . Il détectera toutes
les interactions de l'utilisateur, puis enverra les événements suivants :
• Événement PointerDown
• PointerMoveEvent
• Événement PointerUp
• PointerCancelEvent
Flutter fournit également un petit ensemble de widgets permettant d'effectuer des gestes spécifiques et avancés.
Les widgets sont répertoriés cidessous :
• LongPressDraggable : prend en charge le geste de glissement pour déplacer un widget, lorsque son parent
le widget est également déplaçable.
• AbsorbPointer : arrête le processus de détection de gestes luimême et ainsi tout widget qui se chevauche ne peut pas
non plus participer au processus de détection de gestes et par conséquent, aucun événement n'est déclenché.
44
Machine Translated by Google
La gestion de l’état dans une application est l’un des processus les plus importants et les plus nécessaires du cycle
de vie d’une application.
• Une fois l'utilisateur connecté, l'application doit conserver les détails de l'utilisateur connecté dans tous les
l'écran.
• De nouveau, lorsque l’utilisateur sélectionne un produit et l’enregistre dans un panier, les informations du panier
doivent persister entre les pages jusqu’à ce que l’utilisateur ait validé le panier.
• Les informations sur l'utilisateur et son panier à tout moment sont appelées l'état de l'application
à ce momentlà.
La gestion d'un état peut être divisée en deux catégories en fonction de la durée d'un état particulier dans une
application.
• Éphémère Dure quelques secondes comme l'état actuel d'une animation ou d'une seule page comme l'évaluation
actuelle d'un produit. Flutter le prend en charge via StatefulWidget.
• État de l'application Dernier pour l'ensemble de l'application, comme les détails de l'utilisateur connecté, les informations sur le panier,
etc., Flutter prend en charge son scoped_model.
Créons un widget, RatingBox avec maintenance de l'état. Le but du widget est d'afficher la note actuelle d'un produit
spécifique. Le processus étape par étape pour créer un widget RatingBox avec maintenance de l'état est le suivant :
45
Machine Translated by Google
Battement
renvoie
Row( mainAxisAlignment : MainAxisAlignment.end,
crossAxisAlignment : CrossAxisAlignment.end,
mainAxisSize : MainAxisSize.max,
enfants :
Container( rembourrage :
EdgeInsets.all(0), enfant : IconButton(
icône : (_rating >= 2 ? Icône(Icons.star, taille : _size,) :
Icône(Icons.star_border, taille : _size,)), couleur :
Colors.red[500], iconSize :
_size, ), ),
Container( rembourrage :
EdgeInsets.all(0), enfant : IconButton(
icône : (_rating >= 3 ? Icône(Icons.star, taille : _size,) :
Icône(Icons.star_border, taille : _size,)), couleur :
Colors.red[500], iconSize :
_size, ), ),
], );
}
46
Machine Translated by Google
Battement
Ici, nous avons utilisé trois étoiles, créées à l'aide du widget IconButton et disposées à l'aide du widget Row sur une seule
ligne. L'idée est d'afficher la note à travers la séquence d'étoiles rouges.
Par exemple, si la note est de deux étoiles, les deux premières étoiles seront rouges et la dernière sera blanche.
void _setRatingAsTwo() {
setState( () { _rating
= 2; });
• Reliez le geste de l’utilisateur (appuyer sur l’étoile) à la méthode de changement d’état appropriée.
renvoie
Row( mainAxisAlignment : MainAxisAlignment.end,
crossAxisAlignment : CrossAxisAlignment.end, mainAxisSize :
MainAxisSize.max, enfants :
<Widget>[ Container( padding :
EdgeInsets.all(0),
enfant : IconButton(
enfant :
IconButton(
47
Machine Translated by Google
Battement
onPressed : _setRatingAsTwo,
iconSize : _size, ), ),
Container( rembourrage :
EdgeInsets.all(0), enfant : IconButton(
icône : (_rating >= 3 ? Icône(Icons.star, taille : _size,) :
Icône(Icons.star_border, taille : _size,)), couleur :
Colors.red[500], onPressed :
_setRatingAsThree, iconSize :
_size, ), ),
], );
}
Ici, l'événement onPressed appelle la fonction appropriée pour modifier l'état et modifier ensuite l'interface
utilisateur. Par exemple, si un utilisateur clique sur la troisième étoile, alors _setRatingAsThree sera appelé
et changera le _rating à 3. Puisque l'état est modifié, la méthode build sera à nouveau appelée et l'interface
utilisateur sera à nouveau générée et rendue.
void _setRatingAsOne()
{ setState( ()
{ _rating = 1; });
void _setRatingAsTwo() {
setState( ()
{ _rating = 2; });
void _setRatingAsThree()
{ setState( ()
{ _rating = 3; });
48
Machine Translated by Google
Battement
renvoie
Row( mainAxisAlignment : MainAxisAlignment.end,
crossAxisAlignment : CrossAxisAlignment.end,
mainAxisSize : MainAxisSize.max,
enfants :
Container( rembourrage :
EdgeInsets.all(0), enfant : IconButton(
icône : (_rating >= 2 ? Icône(Icons.star, taille : _size,) :
Icône(Icons.star_border, taille : _size,)), couleur :
Colors.red[500], onPressed :
_setRatingAsTwo, iconSize :
_size, ), ),
Container( rembourrage :
EdgeInsets.all(0), enfant : IconButton(
icône : (_rating >= 3 ? Icône(Icons.star, taille : _size,) :
Icône(Icons.star_border, taille : _size,)), couleur :
Colors.red[500], onPressed :
_setRatingAsThree, iconSize : _size, ), ),
], );
}
}
Créons une nouvelle application et utilisons notre widget RatingBox nouvellement créé pour afficher la note du
produit.
importer 'package:flutter/material.dart';
49
Machine Translated by Google
Battement
build(BuildContext context) {
return MaterialApp( title:
'Flutter Demo', theme:
ThemeData( primarySwatch:
@override
Widget build(BuildContext context) { return Scaffold( appBar:
AppBar( title:
Texte(this.title), ), corps:
Centre( enfant:
Texte(
'Bonjour le
monde', )),
);
}
}
• Ici,
• Créez un widget ProductBox pour répertorier le produit avec une note comme indiqué cidessous :
50
Machine Translated by Google
Battement
Container( rembourrage :
EdgeInsets.all(5), enfant :
Column( mainAxisAlignment :
MainAxisAlignment.spaceUniformément,
enfants :
])));
}
}
• Mettre à jour le widget MyHomePage pour inclure le widget ProductBox comme spécifié
cidessous:
@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar(title: Text("Product Listing")), body: ListView( shrinkWrap: true,
padding: const
EdgeInsets.fromLTRB(2.0,
10.0, 2.0, 10.0), children: <Widget>[ ProductBox( name: "iPhone", description: "iPhone
est le téléphone le plus stylé
de tous les
temps", prix: 1000,
image: "iphone.png"), ProductBox( name: "Pixel", description: "Pixel est
le téléphone le
plus fonctionnel de tous les
temps", prix:
800, image:
"pixel.png"), ProductBox( name: "Laptop", description: "Laptop est l'outil de
développement
le plus productif",
51
Machine Translated by Google
Battement
prix : 2000,
image : "laptop.png"),
ProductBox( nom :
« Tablette », description : « La tablette est l'appareil le plus utile jamais conçu pour
réunion",
prix : 1500,
image : "tablet.png"),
ProductBox( nom :
« Pendrive », description : « Pendrive est un support de stockage
utile », prix :
100, image : « pendrive.png »),
Boîte de produit(
nom : « Lecteur de disquette »,
description : « Le lecteur de disquette est un stockage de secours utile
moyen",
prix : 20,
image : "floppy.png"),
], ));
}
}
importer 'package:flutter/material.dart';
build(BuildContext context) {
return MaterialApp( title:
'Flutter Demo', theme:
ThemeData( primarySwatch:
@outrepasser
Création de widget (contexte de BuildContext)
{ return
Scaffold( appBar : AppBar(title : Text("Liste de produits")), body :
ListView(
52
Machine Translated by Google
Battement
shrinkWrap : true,
padding : const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), enfants :
<Widget>[ ProductBox( nom :
« iPhone »,
description : « iPhone
est le téléphone le plus stylé de tous les temps », prix : 1 000,
image :
« iphone.png »),
ProductBox( nom :
« Pixel », description : « Pixel est le téléphone le plus riche en fonctionnalités »,
prix : 800,
image : « pixel.png »),
ProductBox( nom :
« Ordinateur portable », description : « L'ordinateur portable est l'outil de
développement
le plus productif », prix : 2000, image : « ordinateur portable.png »),
ProductBox( nom :
« Tablette », description : « La tablette est l'appareil le plus utile jamais conçu pour
réunion",
prix : 1500,
image : "tablet.png"),
ProductBox( nom :
« Pendrive », description : « iPhone est le téléphone le plus stylé
de tous les
temps », prix : 100, image :
« pendrive.png »), ProductBox(
nom : « Lecteur de
disquette », description : « L'iPhone est le téléphone le plus stylé
de tous les
temps », prix : 20, image : « floppy.png »),
ProductBox( nom :
« iPhone », description : « iPhone est le téléphone le plus stylé de
tous les temps »,
prix : 1 000, image : « iphone.png »),
ProductBox( nom :
« iPhone », description : « iPhone est le téléphone le plus stylé de
tous les temps »,
prix : 1 000, image : « iphone.png »),
], ));
}
}
53
Machine Translated by Google
Battement
int _rating = 0;
void _setRatingAsOne()
{ setState( ()
{ _rating = 1; });
void _setRatingAsTwo() {
setState( ()
{ _rating = 2; });
void _setRatingAsThree()
{ setState( ()
{ _rating = 3; });
renvoie
Row( mainAxisAlignment : MainAxisAlignment.end,
crossAxisAlignment : CrossAxisAlignment.end,
mainAxisSize : MainAxisSize.max,
enfants :
Container( rembourrage :
EdgeInsets.all(0), enfant : IconButton(
icône : (_rating >= 2 ? Icône(Icons.star, taille : _size,) :
Icône(Icons.star_border, taille : _size,)), couleur :
Colors.red[500], onPressed :
_setRatingAsTwo, iconSize :
_size, ), ),
Container( rembourrage :
EdgeInsets.all(0), enfant : IconButton(
icône : (_rating >= 3 ? Icône(Icons.star, taille : _size,) :
Icône(Icons.star_border, taille : _size,)),
54
Machine Translated by Google
Battement
couleur : Colors.red[500],
onPressed : _setRatingAsThree, iconSize :
_size, ), ),
], );
}
}
Container( rembourrage :
EdgeInsets.all(5), enfant :
Column( mainAxisAlignment :
MainAxisAlignment.spaceUniformément,
enfants :
])));
}
}
55
Machine Translated by Google
Battement
• Enfin, exécutez l'application et consultez la page Gestion des états Liste des produits
Résultats présentés ici :
56
Machine Translated by Google
Battement
Cliquer sur l'étoile de notation permet de mettre à jour la note du produit. Par exemple, définir 2 étoiles
La note pour iPhone affichera la note comme cidessous :
Scoped_model fournit trois classes principales pour permettre une gestion d'état robuste dans une
application qui sont décrites en détail ici :
Modèle
Le modèle encapsule l'état d'une application. Nous pouvons utiliser autant de modèles (en héritant de la
classe Model) que nécessaire pour maintenir l'état de l'application. Il possède une seule méthode,
notifyListeners, qui doit être appelée chaque fois que l'état du modèle change. notifyListeners effectuera
les tâches nécessaires pour mettre à jour l'interface utilisateur.
57
Machine Translated by Google
Battement
notifierListeners();
}
}
ScopedModel est un widget qui contient le modèle donné et le transmet ensuite à tous les widgets descendants
si nécessaire. Si plusieurs modèles sont nécessaires, nous devons imbriquer le ScopedModel.
• Modèle unique
ScopedModel<Product>( modèle :
élément, enfant :
AnyWidget()
)
• Modèle multiple
ScopedModel<Product>( modèle :
item1, enfant :
ScopedModel<Product>( modèle :
item2, enfant :
AnyWidget(), ),
ScopedModel.of est une méthode utilisée pour obtenir le modèle sousjacent au ScopedModel. Elle peut être
utilisée lorsqu'aucune modification de l'interface utilisateur n'est nécessaire, même si le modèle va changer.
Ce qui suit ne modifiera pas l'interface utilisateur (évaluation) du produit.
ScopedModel.of<Product>(contexte).updateRating(2);
58
Machine Translated by Google
Battement
ScopedModelDescendant est un widget qui récupère le modèle du widget de niveau supérieur, ScopedModel, et
crée son interface utilisateur chaque fois que le modèle change.
ScopedModelDescendant possède deux propriétés : builder et child. child est la partie de l'interface utilisateur
qui ne change pas et qui sera transmise à builder. builder accepte une fonction avec trois arguments :
• enfant Une partie de l'interface utilisateur qui ne change pas en fonction du modèle.
• modèle Le modèle réel à cet instant.
renvoyer ScopedModelDescendant<ProductModel>(
builder: (context, child, cart) => { ... Interface utilisateur réelle ... }, child:
PartOfTheUI(), );
Modifions notre exemple précédent pour utiliser le modèle Scoped_model au lieu de StatefulWidget
• Remplacez le code de démarrage par défaut (main.dart) par notre code product_state_app.
battement:
actifs:
assets/appimages/floppy.png assets/
appimages/iphone.png assets/
appimages/laptop.png assets/appimages/
pendrive.png assets/appimages/pixel.png
assets/appimages/tablet.png
• Cliquez sur l'option Obtenir les dépendances. Android Studio récupérera le package sur Internet et le
configurera correctement pour l'application.
59
Machine Translated by Google
Battement
• Remplacez le code de démarrage par défaut (main.dart) par notre code de démarrage.
importer 'package:flutter/material.dart';
build(BuildContext context) {
return MaterialApp( title:
'Flutter Demo', theme:
ThemeData( primarySwatch:
@override
Widget build(BuildContext context) { return Scaffold( appBar:
AppBar( title:
Texte(this.title), ), body:
Centre( child: Texte( 'Bonjour le
monde', )),
);
}
}
importer 'package:scoped_model/scoped_model.dart';
• Créons une classe Produit, Product.dart pour organiser les informations produit.
importer 'package:scoped_model/scoped_model.dart';
60
Machine Translated by Google
Battement
notifierListeners();
}
}
Ici, nous avons utilisé notifyListeners pour modifier l'interface utilisateur chaque fois que la note est modifiée.
• Écrivons une méthode getProducts dans la classe Product pour générer notre modèle factice
enregistrements de produits.
items.add(Product( "Pixel",
"Pixel est
le téléphone le plus complet de tous les temps", 800, "pixel.png",
0));
items.add(Product( "Ordinateur
portable",
"L'ordinateur portable est l'outil de développement le plus
items.add(Product( "Tablette",
"La tablette
est l'appareil le plus utile pour les réunions", 1500, "tablet.png", 0));
items.add(Product( "Pendrive",
"Pendrive est
un support de stockage utile", 100, "pendrive.png",
0));
éléments.add(Produit(
61
Machine Translated by Google
Battement
« Lecteur de
disquette », « Le lecteur de disquette est un support de stockage de
importer 'Produit.dart';
• Modifions notre nouveau widget, RatingBox pour prendre en charge le concept scoped_model.
renvoie
Row( mainAxisAlignment : MainAxisAlignment.end,
crossAxisAlignment : CrossAxisAlignment.end, mainAxisSize :
MainAxisSize.max, enfants :
<Widget>[ Container( padding :
EdgeInsets.all(0), enfant :
IconButton( icône :
(item.rating >= 1 ?
Icône( Icons.star,
taille : _size,
)
:
Icône( Icons.star_border,
taille : _size, )),
couleur : Colors.red[500],
onPressed : () => this.item.updateRating(1), iconSize :
_size, ), ),
Icône( Icons.star,
taille : _size,
)
:
Icône( Icônes.star_border,
taille : _size,
62
Machine Translated by Google
Battement
)),
couleur : Colors.red[500],
onPressed : () => this.item.updateRating(2), iconSize :
_size, ), ),
)
:
Icône( Icônes.star_border,
taille : _size, )),
couleur : Colors.red[500],
onPressed : () => this.item.updateRating(3), iconSize :
_size, ), ), ], );
}
}
• Modifions notre widget ProductBox pour qu'il fonctionne avec Product, ScopedModel et
Classe ScopedModelDescendant.
EdgeInsets.all(5), enfant :
ScopedModel<Product>( modèle :
this.item, enfant : Column(
63
Machine Translated by Google
Battement
mainAxisAlignment :
MainAxisAlignment.spaceÉgalité, enfants :
<Widget>[
Texte(cet.élément.nom, style :
TextStyle(fontWeight :
FontWeight.bold)),
Texte(cet.élément.description), Texte("Prix :
" +
cet.article.prix.toString()),
ScopedModelDescendant<Produit>(
constructeur : (contexte, enfant, élément) {
renvoie RatingBox(élément : élément); }) ], ))))
]),
));
}
}
@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar(title: Text("Navigation du produit")), body: ListView.builder(
itemCount : éléments.length,
itemBuilder : (contexte, index) { return
ProductBox(élément : éléments[index]); }, ));
}
}
Ici, nous avons utilisé ListView.builder pour créer dynamiquement notre liste de produits.
Produit.dart
importer 'package:scoped_model/scoped_model.dart';
64
Machine Translated by Google
Battement
vide cn
"L'ordinateur portable est l'outil de développement le plus
items.add(Product( "Tablet"cnvn, "La tablette est l'appareil le plus utile pour les
items.add(Product( "Pendrive",
"Pendrive est
un support de stockage utile", 100, "pendrive.png",
0));
items.add(Product( "Lecteur
de disquette", "Le
lecteur de disquette est un support de stockage de secours utile",
20,
"floppy.png", 0));
65
Machine Translated by Google
Battement
@outrepasser
Création de widget (contexte BuildContext) {
return MaterialApp( title:
'Flutter Demo', theme:
ThemeData( primarySwatch:
Colors.blue, ), home: MyHomePage(title:
}
}
@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar(title: Text("Navigation du produit")), body: ListView.builder(
itemCount : éléments.length,
itemBuilder : (contexte, index) { return
ProductBox(élément : éléments[index]); }, ));
}
}
renvoie
Row( mainAxisAlignment : MainAxisAlignment.end,
crossAxisAlignment : CrossAxisAlignment.end, mainAxisSize :
MainAxisSize.max, enfants :
<Widget>[ Container( padding :
EdgeInsets.all(0), enfant :
IconButton( icône :
(item.rating >= 1 ?
Icône( Icons.star,
taille : _size,
)
: Icône(
66
Machine Translated by Google
Battement
Icônes.star_border, taille :
_size, )), couleur :
Colors.red[500], onPressed : ()
=> this.item.updateRating(1), iconSize : _size, ), ),
Container( rembourrage :
EdgeInsets.all(0), enfant :
IconButton( icône :
(item.rating >= 2 ?
Icône( Icônes.star,
taille : _size,
)
:
Icône( Icons.star_border,
taille : _size, )),
couleur : Colors.red[500],
onPressed : () => this.item.updateRating(2), iconSize :
_size, ), ),
Icône( Icons.star,
taille : _size,
)
:
Icône( Icônes.star_border,
taille : _size, )),
couleur : Colors.red[500],
onPressed : () => this.item.updateRating(3), iconSize :
_size, ), ), ], );
}
}
67
Machine Translated by Google
Battement
hauteur : 140,
enfant :
Card( enfant : Row(
mainAxisAlignment : MainAxisAlignment.spaceEvenly, enfants :
<Widget>[ Image.asset("assets/
appimages/" + this.item.image), Expanded( enfant :
Container( rembourrage :
EdgeInsets.all(5), enfant :
ScopedModel<Product>( modèle :
this.item, enfant :
Column( mainAxisAlignment :
MainAxisAlignment.spaceEvenly,
enfants : <Widget>[
Texte(cet.élément.nom,
style :
TextStyle(fontWeight :
FontWeight.bold)),
Texte(cet.élément.description),
Texte("Prix : " +
cet.article.prix.toString()),
ScopedModelDescendant<Produit>(
constructeur : (contexte, enfant, élément) {
renvoie RatingBox(élément :
élément); }) ], ))))
]),
));
}
}
Enfin, compilez et exécutez l'application pour voir son résultat. Cela fonctionnera de manière similaire à l'exemple
précédent, sauf que l'application utilise le concept de modèle de portée.
Navigation et routage
Dans toute application, la navigation d'une page/d'un écran à un autre définit le flux de travail de l'application. La
manière dont la navigation dans une application est gérée s'appelle le routage.
Flutter fournit une classe de routage de base MaterialPageRoute et deux méthodes Navigator.push et
Navigator.pop, pour définir le flux de travail d'une application.
MatérielPageRoute
MaterialPageRoute est un widget utilisé pour restituer son interface utilisateur en remplaçant l'intégralité de l'écran par une
animation spécifique à la plateforme.
Ici, le constructeur accepte une fonction pour construire son contenu en fournissant le contexte actuel de
l'application.
Navigation.push
68
Machine Translated by Google
Battement
Navigation.push est utilisé pour naviguer vers un nouvel écran à l'aide du widget MaterialPageRoute.
Navigator.push(contexte,
Navigation.pop
Navigation.pop est utilisé pour naviguer vers l'écran précédent.
Navigateur.push(contexte);
• Copiez le dossier des ressources de product_nav_app vers product_state_app et ajoutez des ressources
à l'intérieur du fichier pubspec.yaml
battement:
actifs:
assets/appimages/floppy.png assets/
appimages/iphone.png assets/appimages/
laptop.png assets/appimages/
pendrive.png assets/appimages/pixel.png
assets/appimages/tablet.png
• Remplacez le code de démarrage par défaut (main.dart) par notre code de démarrage.
importer 'package:flutter/material.dart';
}
}
69
Machine Translated by Google
Battement
@override
Widget build(BuildContext context) { return Scaffold( appBar:
AppBar( title:
Texte(this.title), ), body:
Centre( child: Texte( 'Bonjour le
monde', )),
);
}
}
classe Produit
{ chaîne finale nom ;
chaîne finale description ; int final
prix ; chaîne finale
image ;
• Écrivons une méthode getProducts dans la classe Product pour générer notre modèle factice
enregistrements de produits.
items.add(Product( "Pixel",
"Pixel est
le téléphone le plus complet de tous les temps", 800,
"pixel.png"));
items.add(Product( "Ordinateur
portable",
"L'ordinateur portable est l'outil de développement le plus
items.add(Product( "Tablette",
"La tablette
est l'appareil le plus utile pour les réunions", 1500, "tablette.png"));
items.add(Product( "Pendrive",
"Pendrive est
un support de stockage utile",
70
Machine Translated by Google
Battement
100,
"clé USB.png"));
items.add(Product( "Lecteur
de disquette", "Le
lecteur de disquette est un support de stockage de secours utile",
20,
"floppy.png"));
importer 'Produit.dart';
void _setRatingAsOne()
{ setState(()
{ _rating = 1; });
void _setRatingAsTwo()
{ setState(()
{ _rating = 2; });
void _setRatingAsThree() {
setState(() { _rating
= 3; });
renvoie
Row( mainAxisAlignment : MainAxisAlignment.end,
crossAxisAlignment : CrossAxisAlignment.end, mainAxisSize :
MainAxisSize.max, enfants :
<Widget>[ Container( padding :
71
Machine Translated by Google
Battement
Icône( Icônes.star,
taille : _size,
)
:
Icône( Icons.star_border,
taille : _size, )),
couleur : Colors.red[500],
onPressed : _setRatingAsOne,
iconSize : _size, ), ),
Icône( Icônes.star,
taille : _size,
)
:
Icône( Icônes.star_border,
taille : _size, )),
couleur : Colors.red[500],
onPressed : _setRatingAsTwo,
iconSize : _size, ), ),
Icône( Icônes.star,
taille : _size,
)
:
Icône( Icônes.star_border,
taille : _size, )),
couleur : Colors.red[500],
onPressed : _setRatingAsThree, iconSize :
_size, ), ), ], );
}
}
72
Machine Translated by Google
Battement
• Modifions notre widget ProductBox pour qu’il fonctionne avec notre nouvelle classe Product.
Expanded( enfant :
Container( rembourrage :
EdgeInsets.all(5),
enfant :
Column( mainAxisAlignment : MainAxisAlignment.spaceEvenly,
enfants : <Widget>[
Texte(cet.élément.nom,
style : TextStyle(fontWeight :
FontWeight.bold)),
Texte(cet.élément.description),
Texte("Prix : " + cet.élément.prix.toString()), RatingBox(), ], )))
]),
));
}
}
• Réécrivons notre widget MyHomePage pour qu'il fonctionne avec le modèle Product et pour répertorier tous
les produits à l'aide de ListView.
@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar(title: Text("Navigation du produit")), body: ListView.builder(
itemCount : éléments.length,
itemBuilder : (contexte, index) {
73
Machine Translated by Google
Battement
{ Navigator.push( contexte,
MaterialPageRoute(
constructeur : (contexte) => ProductPage(élément :
éléments[index]),
), ); }, ); }, ));
}
}
Ici, nous avons utilisé MaterialPageRoute pour accéder à la page des détails du produit.
@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar( title:
Texte(this.item.name), ), body:
Centre( child:
Conteneur( padding:
EdgeInsets.all(0),
enfant :
Colonne( mainAxisAlignment : MainAxisAlignment.start,
crossAxisAlignment : CrossAxisAlignment.start, enfants :
<Widget>[ Image.asset("assets/
appimages/" +
cet.élément.image),
Développé( enfant :
Conteneur( rembourrage :
EdgeInsets.all(5),
enfant : Colonne( mainAxisAlignment :
MainAxisAlignment.spaceUniformément,
enfants : <Widget>[
Texte(cet.élément.nom,
style : TextStyle(fontWeight :
FontWeight.bold)),
Texte(cet.élément.description),
Texte("Prix : " +
cet.article.prix.toString()),
Boîte de notation(),
74
Machine Translated by Google
Battement
], )))
]),
),
), );
}
}
importer 'package:flutter/material.dart';
classe Produit
{ chaîne finale nom ;
chaîne finale description ; int final
prix ; chaîne finale
image ;
items.add(Product( "Pixel",
"Pixel est le téléphone le plus riche en fonctionnalités jamais créé", 800,
"pixel.png"));
items.add(Product( "Tablette",
"La tablette
est l'appareil le plus utile pour les réunions", 1500, "tablette.png"));
items.add(Product( "Pendrive",
"iPhone est le téléphone le plus stylé de tous les temps", 100,
"pendrive.png"));
items.add(Product( "Floppy
Drive", "iPhone est le téléphone le plus stylé de tous les temps", 20,
"floppy.png"));
items.add(Product( "iPhone",
"iPhone est le téléphone le plus stylé de tous les temps", 1000,
"iphone.png"));
75
Machine Translated by Google
Battement
}
}
@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar(title: Text("Navigation du produit")), body: ListView.builder(
itemCount : éléments.length,
itemBuilder : (contexte, index) { return
GestureDetector( child :
ProductBox(élément : éléments[index]), onTap : ()
{ Navigator.push( contexte,
MaterialPageRoute(
constructeur : (contexte) => ProductPage(élément :
éléments[index]),
), ); }, ); }, ));
}
}
@outrepasser
Création de widget (contexte BuildContext) { return
Scaffold( appBar:
AppBar(
76
Machine Translated by Google
Battement
titre : Texte(this.item.name), ),
corps :
Centre( enfant :
Conteneur( rembourrage :
EdgeInsets.all(0),
enfant : Colonne( mainAxisAlignment :
MainAxisAlignment.start, crossAxisAlignment :
CrossAxisAlignment.start,
enfants : <Widget>[ Image.asset("assets/appimages/" +
this.item.image),
Expanded( enfant :
]),
),
), );
}
}
void _setRatingAsOne()
{ setState(()
{ _rating = 1; });
void _setRatingAsTwo()
{ setState(()
{ _rating = 2; });
void _setRatingAsThree()
{ setState(() {
77
Machine Translated by Google
Battement
_note = 3; });
renvoie
Row( mainAxisAlignment : MainAxisAlignment.end,
crossAxisAlignment : CrossAxisAlignment.end, mainAxisSize :
MainAxisSize.max, enfants :
<Widget>[ Container( padding :
Icône( Icônes.star,
taille : _size,
)
:
Icône( Icons.star_border,
taille : _size, )),
couleur : Colors.red[500],
onPressed : _setRatingAsOne,
iconSize : _size, ), ),
Icône( Icônes.star,
taille : _size,
)
:
Icône( Icônes.star_border,
taille : _size, )),
couleur : Colors.red[500],
onPressed : _setRatingAsTwo,
iconSize : _size, ), ),
Icône( Icônes.star,
taille : _size,
)
78
Machine Translated by Google
Battement
:
Icône( Icônes.star_border,
taille : _size, )),
couleur : Colors.red[500],
onPressed : _setRatingAsThree,
iconSize :
_size, ), ), ], );
}
}
Expanded( enfant :
Container( rembourrage :
EdgeInsets.all(5),
enfant :
Column( mainAxisAlignment :
MainAxisAlignment.spaceEvenly, enfants : <Widget>[
Texte(cet.élément.nom,
style : TextStyle(fontWeight :
FontWeight.bold)),
Texte(cet.élément.description),
Texte("Prix : " + cet.élément.prix.toString()), RatingBox(), ], )))
]),
));
}
}
79
Machine Translated by Google
Battement
Exécutez l'application et cliquez sur l'un des éléments du produit. La page de détails correspondante
s'affiche. Nous pouvons passer à la page d'accueil en cliquant sur le bouton Retour. La page de liste
des produits et la page de détails des produits de l'application sont présentées comme suit :
80
Machine Translated by Google
Battement
81
Machine Translated by Google
L'animation est une procédure complexe dans toute application mobile. Malgré sa complexité, l'animation améliore l'expérience
utilisateur à un nouveau niveau et offre une interaction utilisateur riche. En raison de sa richesse, l'animation devient partie
intégrante de l'application mobile moderne. Le framework Flutter reconnaît l'importance de l'animation et fournit une
Introduction
L'animation est un processus qui consiste à montrer une série d'images dans un ordre particulier et pendant une durée
déterminée pour donner une illusion de mouvement. Les aspects les plus importants de l'animation sont les suivants :
• L'animation possède deux valeurs distinctes : la valeur de départ et la valeur de fin. L'animation démarre à partir de la valeur
de départ et passe par une série de valeurs intermédiaires pour finalement se terminer aux valeurs de fin . Par exemple,
pour animer un widget afin qu'il disparaisse, la valeur initiale sera l'opacité totale et la valeur finale sera l'opacité nulle.
• Les valeurs intermédiaires peuvent être de nature linéaire ou non linéaire (courbe) et peuvent être configurées. Sachez que
l'animation fonctionne telle qu'elle est configurée. Chaque configuration donne une sensation différente à l'animation.
Par exemple, l'atténuation d'un widget sera de nature linéaire tandis que le rebond d'une balle sera de nature non
linéaire.
• La possibilité de contrôler le processus d'animation comme le démarrage de l'animation, l'arrêt de l'animation, la répétition
de l'animation un nombre défini de fois, l'inversion du processus d'animation, etc.
• Dans Flutter, le système d'animation ne réalise aucune animation réelle. Au lieu de cela, il fournit uniquement les
valeurs requises à chaque image pour restituer les images.
Animation
Génère des valeurs interpolées entre deux nombres sur une certaine durée. Les classes d'animation les plus courantes sont :
82
Machine Translated by Google
Battement
• AnimationController Objet d'animation spécial pour contrôler l'animation ellemême. Il génère de nouvelles valeurs
chaque fois que l'application est prête pour une nouvelle image. Il prend en charge l'animation linéaire et la valeur
commence de 0,0 à 1,0.
Ici, le contrôleur contrôle l'animation et l'option de durée contrôle la durée du processus d'animation. vsync est une
option spéciale utilisée pour optimiser la ressource utilisée dans l'animation.
Animation courbée
Similaire à AnimationController mais prend en charge l'animation non linéaire. CurvedAnimation peut être utilisé avec l'objet
Animation comme cidessous :
Entre <T>
Dérivé de Animatable<T> et utilisé pour générer des nombres compris entre deux nombres autres que 0 et 1. Il peut être
utilisé avec l'objet Animation en utilisant la méthode animate et en passant l'objet Animation réel.
Ici, le contrôleur est le contrôleur d'animation réel. curve fournit le type de nonlinéarité et customTween fournit une plage
personnalisée de 0 à 255.
• Ajouter un écouteur basé sur l'animation, addListener pour changer l'état du widget
83
Machine Translated by Google
Battement
});
• Les widgets intégrés, AnimatedWidget et AnimatedBuilder, peuvent être utilisés pour ignorer ce processus. Les deux
widgets acceptent l'objet Animation et obtiennent les valeurs actuelles requises pour l'animation.
• Obtenez les valeurs d'animation pendant le processus de création du widget, puis appliquezles pour la largeur, la
hauteur ou toute propriété pertinente au lieu de la valeur d'origine.
enfant :
Conteneur( hauteur : animation.value,
largeur : animation.value, enfant :
<Widget>,
)
Application de travail
Écrivons une application simple basée sur une animation pour comprendre le concept d'animation dans le framework Flutter.
• Copiez le dossier assets de product_nav_app vers product_animation_app et ajoutez des assets dans le fichier
pubspec.yaml
battement:
actifs:
assets/appimages/floppy.png
assets/appimages/iphone.png
assets/appimages/ordinateur portable.png
assets/appimages/clé usb.png
assets/appimages/pixel.png
assets/appimages/tablette.png
importer 'package:flutter/material.dart';
84
Machine Translated by Google
Battement
• Créez le widget _MyAppState et implémentez initState et disposez en plus de la méthode de génération par défaut.
Animation<double> animation;
Contrôleur AnimationController ;
@override
void initState() {
super.initState(); contrôleur
= AnimationController(durée : const Durée(secondes : 10), vsync : this);
@override
void dispose()
{ contrôleur.dispose();
super.dispose();
}
}
Ici,
• Dans la méthode initState, nous avons créé un objet contrôleur d'animation (controller), un objet d'animation
(animation) et démarré l'animation à l'aide de controller.forward.
• Dans la méthode dispose, nous avons disposé l'objet contrôleur d'animation (contrôleur).
• Dans la méthode build, envoyez l'animation au widget MyHomePage via le constructeur. Désormais, le widget
MyHomePage peut utiliser l'objet animation pour animer son contenu.
85
Machine Translated by Google
Battement
: super(clé: clé);
Container( padding:
EdgeInsets.all(5), enfant:
])));
}
}
• Créez un nouveau widget, MyAnimatedWidget pour réaliser une animation de fondu simple en utilisant l'opacité.
);
}
• Ici, nous avons utilisé AniatedBuilder pour réaliser notre animation. AnimatedBuilder est un widget qui
construit son contenu tout en réalisant l'animation en même temps. Il accepte un objet d'animation pour
obtenir la valeur d'animation actuelle. Nous avons utilisé animation
86
Machine Translated by Google
Battement
valeur, animation.valeur pour définir l'opacité du widget enfant. En effet, le widget animera le widget
enfant en utilisant le concept d'opacité.
• Enfin, créez le widget MyHomePage et utilisez l’objet d’animation pour animer n’importe lequel de
son contenu.
@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar(title: Text("Product Listing")), body: ListView( shrinkWrap:
true, padding: const
EdgeInsets.fromLTRB(2.0,
10.0, 2.0, 10.0), children: <Widget>[ FadeTransition(child: ProductBox( name:
"iPhone", description:
"iPhone est le téléphone le plus stylé de tous
les temps", prix:
1000, image: "iphone.png"), opacity: animation),
MyAnimatedWidget(child:
ProductBox( name: "Pixel",
description: "Pixel est le téléphone le plus riche
en fonctionnalités
de tous les temps", prix: 800, image: "pixel.png"),
animation : animation),
ProductBox( nom :
« Ordinateur portable », description : « L'ordinateur portable est l'outil de
développement
le plus productif », prix :
2 000, image :
« laptop.png »),
ProductBox( nom : « Tablette », description : « La tablette est l'appareil le plus utile de tous les temps
réunion",
prix : 1500,
image : "tablet.png"),
ProductBox( nom :
"Pendrive", description : "Pendrive est un support de stockage
utile", prix :
100, image : "pendrive.png"),
87
Machine Translated by Google
Battement
));
}
}
Ici, nous avons utilisé FadeAnimation et MyAnimationWidget pour animer les deux premiers
éléments de la liste. FadeAnimation est une classe d'animation intégrée, que nous avons utilisée
pour animer son enfant en utilisant le concept d'opacité.
importer 'package:flutter/material.dart';
Animation<double> animation;
Contrôleur AnimationController ;
@override
void initState() {
super.initState();
contrôleur = AnimationController(durée : const Durée(secondes : 10), vsync : this);
animation =
Tween<double>(début : 0,0, fin : 1,0).animate(contrôleur); contrôleur.forward();
@override
void dispose()
{ contrôleur.dispose();
super.dispose();
}
}
88
Machine Translated by Google
Battement
@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar(title: Text("Product Listing")), body: ListView( shrinkWrap:
true, padding: const
EdgeInsets.fromLTRB(2.0,
10.0, 2.0, 10.0), children: <Widget>[ FadeTransition(child: ProductBox( name:
"iPhone", description:
"iPhone est le téléphone le plus stylé de tous
les temps", prix:
1000, image: "iphone.png"), opacity: animation),
MyAnimatedWidget(child:
ProductBox( name: "Pixel",
description: "Pixel est le téléphone le plus riche
en fonctionnalités
de tous les temps", prix: 800, image: "pixel.png"),
animation : animation),
ProductBox( nom :
« Ordinateur portable », description : « L'ordinateur portable est l'outil de
développement
le plus productif », prix :
2 000, image :
« laptop.png »),
ProductBox( nom : « Tablette », description : « La tablette est l'appareil le plus utile de tous les temps
réunion",
prix : 1500,
image : "tablet.png"),
ProductBox( nom :
« Pendrive », description : « Pendrive est un support de stockage
utile », prix :
100, image : « pendrive.png »),
ProductBox(
nom : « Lecteur de disquette »,
description : « Le lecteur de disquette est un stockage de secours utile
moyen",
prix : 20,
image : "floppy.png"),
], ));
}
}
89
Machine Translated by Google
Battement
Container( padding:
EdgeInsets.all(5), enfant:
])));
}
}
);
}
90
Machine Translated by Google
Battement
• Compilez et exécutez l'application pour voir les résultats. La version initiale et finale de
l'application est la suivante :
91
Machine Translated by Google
Battement
92
Machine Translated by Google
Flutter fournit un cadre général pour accéder à des fonctionnalités spécifiques à la plateforme. Cela permet au
développeur d'étendre les fonctionnalités du framework Flutter à l'aide d'un code spécifique à la plateforme.
Les fonctionnalités spécifiques à la plateforme telles que l'appareil photo, le niveau de la batterie, le navigateur, etc. sont
facilement accessibles via le framework.
L'idée générale d'accès au code spécifique de la plateforme se fait via un protocole de messagerie simple. Le code
Flutter, le client, le code de la plateforme et l'hôte se lient à un canal de messages commun. Le client envoie un message
à l'hôte via le canal de messages. L'hôte écoute sur le canal de messages, reçoit le message et effectue les fonctionnalités
nécessaires et enfin, renvoie le résultat au client via le canal de messages.
L'architecture du code spécifique à la plateforme est illustrée dans le schéma fonctionnel cidessous :
Le protocole de messagerie utilise un codec de message standard (classe StandardMessageCodec) qui prend en charge
la sérialisation binaire de valeurs de type JSON telles que des nombres, des chaînes, des booléens, etc. La sérialisation
et la désérialisation fonctionnent de manière transparente entre le client et le
hôte.
Écrivons une application simple pour ouvrir un navigateur à l’aide du SDK Android et comprenons comment invoquer le
SDK à partir de l’application Flutter.
importer 'package:flutter/material.dart';
93
Machine Translated by Google
Battement
);
}
}
@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar( title:
Texte(this.title), ), body: Center( child:
RaisedButton( child:
Texte('Ouvrir le navigateur'),
onPressed: null, ), ), );
}
}
• Ici, nous avons créé un nouveau bouton pour ouvrir le navigateur et défini sa méthode onPressed sur null.
importer 'dart:async';
importer 'package:flutter/services.dart';
• Écrivez une méthode, _openBrowser pour invoquer une méthode spécifique à la plateforme, la méthode
openBrowser via le canal de message.
}
}
94
Machine Translated by Google
Battement
Ici, nous avons utilisé platform.invokeMethod pour invoquer openBrowser (expliqué dans les étapes à venir).
openBrowser a un argument, url pour ouvrir une URL spécifique.
surPressé : _openBrowser,
private void openBrowser(MethodCall call, Result result, String url) { Activity activity = this; if (activity
== null)
activité.startActivity(intention);
résultat.success((Objet) true);
}
• Écrivez du code spécifique à Android pour définir la gestion des messages dans la méthode onCreate.
si (call.method.equals("openBrowser")) {
95
Machine Translated by Google
Battement
{ résultat.notImplemented();
}
}
});
Ici, nous avons créé un canal de messages en utilisant la classe MethodChannel et utilisé la classe
MethodCallHandler pour gérer le message. onMethodCall est la méthode réelle chargée d'appeler le code
spécifique à la plateforme correcte en vérifiant le message. La méthode onMethodCall extrait l'URL du
message, puis appelle openBrowser uniquement lorsque l'appel de méthode est openBrowser. Sinon, elle
renvoie la méthode notImplemented.
main.dart
Activité principale.java
paquet com.tutorialspoint.flutterapp.flutter_browser_app;
importer android.app.Activity;
importer android.content.Intent; importer
android.net.Uri; importer
android.os.Bundle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
si (call.method.equals("openBrowser"))
{ openBrowser(call, result, url); } else
{ result.notImplemented();
}
96
Machine Translated by Google
Battement
});
}
activité.startActivity(intention);
résultat.success((Objet) true);
}
}
main.dart
importer 'package:flutter/material.dart';
importer 'dart:async';
importer 'package:flutter/services.dart';
}
}
97
Machine Translated by Google
Battement
@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar( title:
Texte(this.title), ), body:
Center( child:
RaisedButton( child:
Texte('Ouvrir le navigateur'),
onPressed: _openBrowser, ), ), );
}
}
Exécutez l'application et cliquez sur le bouton Ouvrir le navigateur. Vous verrez que le navigateur est lancé.
La page d'accueil de l'application Navigateur est telle qu'illustrée dans la capture d'écran ici :
98
Machine Translated by Google
Battement
99
Machine Translated by Google
L'accès au code spécifique à iOS est similaire à celui de la plateforme Android, à l'exception du fait qu'il utilise des
langages spécifiques à iOS : ObjectiveC ou Swift et iOS SDK. Sinon, le concept est le même que celui de la plateforme
Android.
Écrivons la même application que dans le chapitre précédent pour la plateforme iOS également.
• Ouvrez AppDelegate.m sous Runner > Chemin Runner. Il contient les éléments suivants
code:
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
//
[GeneratedPluginRegistrant registerWithRegistry:self];
// Point de remplacement pour la personnalisation après le lancement de l'application.
retourner [super application:application
didFinishLaunchingWithOptions:launchOptions];
}
@fin
• Nous avons ajouté une méthode, openBrowser, pour ouvrir le navigateur avec l'URL spécifiée.
accepte un seul argument, url.
(void)openBrowser:(NSString *)urlString {
NSURL *url = [NSURL URLWithString:urlString];
UIApplication *application = [UIApplication sharedApplication];
[application openURL:url];
}
100
Machine Translated by Google
Battement
FlutterViewController* contrôleur =
(FlutterViewController*)self.window.rootViewController;
méthodeChannelWithName:@"flutterapp.tutorialspoint.com/browser"
binaryMessenger:contrôleur];
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
méthodeChannelWithName:@"flutterapp.tutorialspoint.com/browser"
binaryMessenger:contrôleur];
101
Machine Translated by Google
Battement
(void)openBrowser:(NSString *)urlString {
NSURL *url = [NSURL URLWithString:urlString];
UIApplication *application = [UIApplication sharedApplication];
[application openURL:url];
}
@fin
• Maintenant, exécutez l'application. Son fonctionnement est similaire à celui de la version Android, mais le
navigateur Safari s'ouvrira à la place de Chrome.
102
Machine Translated by Google
La méthode utilisée par Dart pour organiser et partager un ensemble de fonctionnalités est le Package. Le Package
Dart est simplement constitué de bibliothèques ou de modules partageables. En général, le Package Dart est identique
à celui de l'Application Dart, sauf que le Package Dart n'a pas de point d'entrée d'application, main.
importer 'package:mon_package_de_démo/mon_package_de_démo.dart'
• D'autres fichiers de code privés peuvent être exportés dans le fichier de code principal
(my_demo_package.dart), si nécessaire, comme indiqué cidessous :
exporter src/mon_code_privé.dart
• lib/* : N'importe quel nombre de fichiers de code Dart organisés dans n'importe quelle structure de dossier personnalisée.
Le code est accessible comme suit :
importer 'package:mon_package_de_démo/dossier_personnalisé/fichier_personnalisé.dart'
Tous les fichiers de code Dart du package sont simplement des classes Dart et il n'y a aucune exigence particulière
pour qu'un code Dart soit inclus dans un package.
Types de forfaits
Étant donné que les packages Dart sont essentiellement une petite collection de fonctionnalités similaires, ils peuvent
être classés en fonction de leurs fonctionnalités.
Paquet de fléchettes
Code Dart générique, qui peut être utilisé à la fois dans un environnement Web et mobile. Par exemple, english_words est
un de ces packages qui contient environ 5000 mots et dispose de fonctions utilitaires de base comme les noms (liste des
noms en anglais), les syllabes (spécification du nombre de syllabes dans un mot).
Paquet Flutter
Code Dart générique, qui dépend du framework Flutter et ne peut être utilisé que dans un environnement mobile. Par
exemple, fluro est un routeur personnalisé pour Flutter. Il dépend du framework Flutter
cadre.
103
Machine Translated by Google
Battement
Plugin Flutter
Code Dart générique, qui dépend du framework Flutter ainsi que du code de la plateforme sousjacente (SDK Android ou SDK iOS).
Par exemple, camera est un plugin permettant d'interagir avec la caméra de l'appareil. Il dépend du framework Flutter ainsi que du
framework sousjacent pour accéder à la caméra.
Les packages Dart sont hébergés et publiés sur le serveur en direct, https://pub.dartlang.org.
De plus, Flutter fournit un outil simple, pub, pour gérer les packages Dart dans l'application. Les étapes nécessaires
pour l'utiliser comme package sont les suivantes :
• Inclure le nom du package et la version nécessaire dans le fichier pubspec.yaml comme indiqué
cidessous:
dépendances:
mots_anglais: ^3.1.5
• Lors du développement dans Android Studio, Android Studio détecte toute modification dans le fichier pubspec.yaml et
affiche une alerte de package Android Studio au développeur, comme indiqué cidessous :
• Les packages Dart peuvent être installés ou mis à jour dans Android Studio à l'aide des options
de menu.
importer 'package:english_words/english_words.dart';
noms.take(50).forEach(print);
• Ici, nous avons utilisé la fonction des noms pour obtenir et imprimer les 50 premiers mots.
Le développement d'un plugin Flutter est similaire au développement d'une application Dart ou d'un package Dart.
La seule exception est que le plugin va utiliser l'API système (Android ou iOS) pour obtenir les fonctionnalités
spécifiques à la plateforme requises.
Comme nous avons déjà appris comment accéder au code de la plateforme dans les chapitres précédents,
développons un plugin simple, my_browser pour comprendre le processus de développement du plugin.
104
Machine Translated by Google
Battement
La fonctionnalité du plugin my_browser est de permettre à l'application d'ouvrir le site Web donné dans le
navigateur spécifique à la plateforme.
• Cliquez sur Fichier > Nouveau projet Flutter et sélectionnez l’option Plugin Flutter.
• Vous pouvez voir une fenêtre de sélection de plugin Flutter comme indiqué ici :
105
Machine Translated by Google
Battement
• Saisissez le nom du plugin et d’autres détails dans la fenêtre comme indiqué ici :
106
Machine Translated by Google
Battement
• Ouvrez le fichier my_browser.dart et écrivez une méthode, openBrowser pour invoquer la plateforme
méthode openBrowser spécifique.
• Ici, nous devons importer la bibliothèque requise pour ouvrir un navigateur depuis Android.
• Ajouter une nouvelle variable privée mRegistrar de type Registrar dans la classe MyBrowserPlugin.
• Ici, Registrar est utilisé pour obtenir des informations contextuelles sur le code d'appel.
• Modifiez registerWith pour inclure notre nouveau constructeur dans la classe MyBrowserPlugin.
@Override
public void onMethodCall(MethodCall appel, Résultat résultat) {
107
Machine Translated by Google
Battement
si (call.method.equals("getPlatformVersion")) { résultat.success("Android
" + android.os.Build.VERSION.RELEASE); } sinon si (call.method.equals("openBrowser"))
{
openBrowser(appel, résultat, url); } else
{ résultat.notImplemented();
}
}
activité.startActivity(intention);
résultat.success((Objet) true);
}
mon_navigateur.dart
importer 'dart:async';
importer 'package:flutter/services.dart';
classe MonNavigateur {
statique const MethodChannel _channel = const
MethodChannel('mon_navigateur');
108
Machine Translated by Google
Battement
}
}
MonPluginBrowser.java
paquet com.tutorialspoint.flutterplugins.my_browser;
MyBrowserPlugin(registrar); channel.setMethodCallHandler(instance);
@Override
public void onMethodCall(MethodCall appel, Résultat résultat) {
Chaîne url = appel.argument("url");
si (call.method.equals("getPlatformVersion")) { résultat.success("Android
" + android.os.Build.VERSION.RELEASE); } sinon si (call.method.equals("openBrowser"))
{
openBrowser(appel, résultat, url); } else
{ résultat.notImplemented();
}
}
109
Machine Translated by Google
Battement
activité.startActivity(intention);
résultat.success((Objet) true);
}
}
• Créez un nouveau projet, my_browser_plugin_test pour tester notre plugin nouvellement créé.
dépendances : flutter :
SDK : Flutter
mon_navigateur :
chemin : ../mon_navigateur
• Android Studio avertira que le fichier pubspec.yaml est mis à jour comme indiqué dans l'alerte du package
Android Studio cidessous :
• Cliquez sur l'option Obtenir les dépendances. Android Studio récupérera le package sur Internet et le
configurera correctement pour l'application.
importer 'package:mon_navigateur/mon_navigateur.dart';
ThemeData( primarySwatch :
110
Machine Translated by Google
Battement
}
}
@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar( title:
Texte(this.title), ), body:
Center( child:
RaisedButton( child:
Texte('Ouvrir le navigateur'),
onPressed: () => MyBrowser().openBrowser("https://flutter.dev"), ), ), );
}
}
111
Machine Translated by Google
Battement
• Exécutez l'application et cliquez sur le bouton Ouvrir le navigateur pour voir si le navigateur est lancé. Vous pouvez voir
une application Navigateur Page d'accueil comme indiqué dans la capture d'écran cidessous :
112
Machine Translated by Google
Battement
• Vous pouvez voir une application de navigateur – écran de navigateur comme indiqué dans la capture d'écran cidessous
cidessous:
113
Machine Translated by Google
Flutter fournit un package http pour consommer des ressources HTTP. http est une bibliothèque basée sur Future
et utilise les fonctionnalités wait et async. Il fournit de nombreuses méthodes de haut niveau et simplifie le
développement d'applications mobiles basées sur REST.
Concepts de base
Le package http fournit une classe de haut niveau et http pour effectuer des requêtes Web.
• La classe http fournit des fonctionnalités permettant d’effectuer tous les types de requêtes HTTP.
• Les méthodes http acceptent une URL et des informations supplémentaires via Dart Map (données de
publication, entêtes supplémentaires, etc.). Elles demandent au serveur et récupèrent la réponse dans
le modèle async/await. Par exemple, le code cidessous lit les données de l'URL spécifiée et les imprime
dans la console.
imprimer(attendre http.read('https://flutter.dev/'));
• read Demande l'URL spécifiée via la méthode GET et renvoie la réponse sous la forme Future<String>
• get Demande l'URL spécifiée via la méthode GET et renvoie la réponse sous la forme Future<Response>.
Response est une classe contenant les informations de réponse.
• post Demande l'URL spécifiée via la méthode POST en publiant les données fournies et renvoie la réponse
sous la forme Future<Response>
http fournit également une classe client HTTP plus standard, client. Le client prend en charge les connexions
persistantes. Il sera utile lorsqu'un grand nombre de requêtes doivent être adressées à un serveur particulier. Il
doit être fermé correctement à l'aide de la méthode close. Sinon, il est similaire à la classe http. L'exemple de
code est le suivant :
114
Machine Translated by Google
Battement
Accéder à ProductserviceAPI
Créons une application simple pour obtenir des données produit à partir d'un serveur Web, puis affichons les produits
à l'aide de ListView.
• Remplacez le code de démarrage par défaut (main.dart) par notre code product_nav_app .
battement:
actifs:
assets/appimages/floppy.png assets/
appimages/iphone.png assets/
appimages/laptop.png assets/appimages/
pendrive.png assets/appimages/pixel.png
assets/appimages/tablet.png
dépendances :
http: ^0.12.0+2
• Ici, nous utiliserons la dernière version du package http. Android Studio enverra une alerte de package
indiquant que le fichier pubspec.yaml est mis à jour.
• Cliquez sur l'option Obtenir les dépendances. Android Studio récupérera le package sur Internet et le
configurera correctement pour l'application.
importer 'dart:async';
importer 'dart:convert'; importer
'package:http/http.dart' comme http;
• Créez un nouveau fichier JSON, products.json avec les informations sur le produit comme indiqué cidessous :
[
{
"nom": "iPhone",
"description": "iPhone est le téléphone le plus stylé de tous les temps",
"prix": 1000,
"image": "iphone.png"
},
{
"name": "Pixel",
"description": "Pixel est le téléphone le plus complet jamais conçu", "price":
800, "image":
"pixel.png"
115
Machine Translated by Google
Battement
},
{
"name": "Laptop",
"description": "L'ordinateur portable est l'outil de développement le plus productif",
"price": 2000,
"image": "laptop.png"
},
{
"name": "Tablet",
"description": "La tablette est l'appareil le plus utile pour les réunions", "price": 1500, "image":
"tablet.png"
},
{
"name": "Pendrive",
"description": "Pendrive est un support de stockage utile", "price": 100,
"image":
"pendrive.png"
},
{
"name": "Lecteur de disquette",
"description": "Le lecteur de disquette est un support de stockage de secours utile", "price":
20, "image":
"floppy.png"
}
]
• Exécutez n’importe quel serveur Web avec JSONWebServer comme répertoire racine et obtenez son chemin Web.
Par exemple, http://192.168.184.1:8000/products.json. Nous pouvons utiliser n'importe quel serveur Web comme
Apache, Nginx, etc.
• Le moyen le plus simple est d'installer une application de serveur http basée sur un nœud. Suivez les étapes indiquées
cidessous pour installer et exécuter l'application serveur http.
cd /chemin/vers/JSONWebServer
116
Machine Translated by Google
Battement
http://127.0.0.1:8000 Appuyez
sur CTRLC pour arrêter le serveur
• Créez un nouveau fichier, Product.dart dans le dossier lib et déplacezy la classe Product.
• Écrivez un constructeur d'usine dans la classe Product, Product.fromMap pour convertir les données mappées
Map en objet Product. Normalement, le fichier JSON sera converti en objet Dart Map, puis converti en objet
pertinent (Product)
Produit( données['nom'],
données['description'],
données['prix'],
données['image'], );
}
classe Produit
{ chaîne finale nom ;
chaîne finale description ; int final
prix ; chaîne finale
image ;
}
}
• Écrivez deux méthodes parseProducts et fetchProducts dans la classe principale pour récupérer et charger
les informations sur le produit à partir du serveur Web dans l'objet List<Product>.
si (réponse.statusCode == 200) {
return parseProducts(response.body); } else { throw
117
Machine Translated by Google
Battement
}
}
• Future est utilisé pour charger les informations du produit en différé. Le chargement différé est un concept
permettant de différer l'exécution du code jusqu'à ce que cela soit nécessaire.
• json.decode est utilisé pour décoder les données JSON dans l'objet Dart Map. Une fois les données JSON décodées,
elles seront converties en List<Product> à l'aide de fromMap de la classe Product.
• Dans la classe MyApp, ajoutez une nouvelle variable membre, des produits de type Future<Product> et incluezla
dans le constructeur.
...
• Dans la classe MyHomePage, ajoutez une nouvelle variable membre products de type Future<Product>
et incluezla dans le constructeur. Supprimez également la variable items et sa méthode
correspondante, l'appel à la méthode getProducts. Placez la variable products dans le constructeur.
Cela permettra de récupérer les produits sur Internet une seule fois au premier démarrage de
l'application.
accueil : MaPageD'Accueil(
titre : « Page d'accueil de démonstration de navigation produit »,
produits : produits),
• Créez un nouveau widget, ProductBoxList pour créer la liste des produits sur la page d'accueil.
118
Machine Translated by Google
Battement
@override
Widget build(BuildContext contexte) { return
ListView.builder(
itemCount : éléments.length,
itemBuilder : (contexte, index) { return
GestureDetector( child :
ProductBox(élément : éléments[index]), onTap : ()
{ Navigator.push( contexte,
MaterialPageRoute(
constructeur : (contexte) => ProductPage(élément : éléments[index]), ), ); }, ); }, );
}
}
Notez que nous avons utilisé le même concept utilisé dans l'application de navigation pour répertorier le produit, sauf qu'il est
conçu comme un widget séparé en passant des produits (objet) de type List<Product>.
renvoie snapshot.hasData ?
ProductBoxList( éléments :
snapshot.data) // renvoie le widget ListView
: Centre(enfant: CircularProgressIndicator());
}, ), ));
}
• Notez ici que nous avons utilisé le widget FutureBuilder pour restituer le widget. FutureBuilder
essaiera de récupérer les données de sa future propriété (de type Future<List<Product>>).
Si la future propriété renvoie des données, elle rendra le widget à l'aide de ProductBoxList, sinon elle génère
une erreur.
119
Machine Translated by Google
Battement
importer 'package:flutter/material.dart';
importer 'dart:async';
importer 'dart:convert';
importer 'package:http/http.dart' comme http;
importer 'Produit.dart';
si (réponse.statusCode == 200) {
return parseProducts(response.body); } else
{ throw
Exception('Impossible de récupérer les produits depuis l'API REST');
}
}
build(BuildContext context) {
return MaterialApp( title:
'Flutter Demo', theme:
ThemeData( primarySwatch:
Colors.blue, ), home:
MyHomePage( title: 'Page d'accueil de démonstration de navigation
produit',
products: products), );
}
}
120
Machine Translated by Google
Battement
@outrepasser
Création de widget (contexte de construction)
{ return Scaffold
(appBar : AppBar (titre : Texte (« Navigation du produit »)), body :
Center (enfant :
FutureBuilder < Liste < Produit > > (future : produits,
builder : (contexte,
instantané) {
si (snapshot.hasError) print(snapshot.error);
renvoie snapshot.hasData ?
ProductBoxList( éléments :
snapshot.data) // renvoie le widget ListView
: Centre(enfant: CircularProgressIndicator());
}, ), ));
}
}
@override
Widget build(BuildContext contexte) { return
ListView.builder(
itemCount : éléments.length,
itemBuilder : (contexte, index) { return
GestureDetector( child :
ProductBox(élément : éléments[index]), onTap : ()
{ Navigator.push( contexte,
MaterialPageRoute(
constructeur : (contexte) => ProductPage(élément : éléments[index]), ), ); }, ); }, );
}
}
@outrepasser
Création de widget (contexte de construction)
{ return Scaffold(
121
Machine Translated by Google
Battement
appBar :
AppBar( titre : Texte(this.item.name), ),
corps :
Centre( enfant :
Conteneur( rembourrage :
EdgeInsets.all(0),
enfant : Colonne( mainAxisAlignment :
MainAxisAlignment.start, crossAxisAlignment :
CrossAxisAlignment.start,
enfants : <Widget>[ Image.asset("assets/appimages/" +
this.item.image),
Expanded( enfant :
Conteneur( rembourrage :
EdgeInsets.all(5), enfant : Colonne( mainAxisAlignment : MainAxisAlignment.spaceEvenly,
enfants : <Widget>[
Texte(cet.élément.nom,
style : TextStyle(fontWeight :
FontWeight.bold)),
Texte(cet.élément.description),
Texte("Prix : " + cet.élément.prix.toString()), RatingBox(), ], )))
]),
), ), );
}
}
void _setRatingAsOne()
{ setState(()
{ _rating = 1; });
void _setRatingAsTwo()
{ setState(()
{ _rating = 2; });
void _setRatingAsThree()
{ setState(() {
122
Machine Translated by Google
Battement
_note = 3; });
renvoie
Row( mainAxisAlignment : MainAxisAlignment.end,
crossAxisAlignment : CrossAxisAlignment.end, mainAxisSize :
MainAxisSize.max, enfants :
<Widget>[ Container( padding :
Icône( Icônes.star,
taille : _size,
)
:
Icône( Icons.star_border,
taille : _size, )),
couleur : Colors.red[500],
onPressed : _setRatingAsOne,
iconSize : _size, ), ),
Icône( Icônes.star,
taille : _size,
)
:
Icône( Icônes.star_border,
taille : _size, )),
couleur : Colors.red[500],
onPressed : _setRatingAsTwo,
iconSize : _size, ), ),
Icône( Icônes.star,
taille : _size,
)
123
Machine Translated by Google
Battement
:
Icône( Icônes.star_border,
taille : _size, )),
couleur : Colors.red[500],
onPressed : _setRatingAsThree,
iconSize :
_size, ), ), ], );
}
}
Expanded( enfant :
Container( rembourrage :
EdgeInsets.all(5),
enfant :
Column( mainAxisAlignment :
MainAxisAlignment.spaceEvenly, enfants : <Widget>[
Texte(cet.élément.nom,
style : TextStyle(fontWeight :
FontWeight.bold)),
Texte(cet.élément.description),
Texte("Prix : " + cet.élément.prix.toString()), RatingBox(), ], )))
]),
));
}
}
Exécutez enfin l'application pour voir le résultat. Il sera identique à notre exemple de navigation , sauf que les
données proviennent d'Internet et non de données locales et statiques saisies lors du codage de l'application.
124
Machine Translated by Google
Flutter propose de nombreux packages avancés pour travailler avec des bases de données. Les packages les plus
importants sont :
• firebase_database – Utilisé pour accéder et manipuler une base de données NoSQL hébergée dans le cloud
de Google.
SQLite
La base de données SQLite est le moteur de base de données intégré basé sur SQL de facto et standard. Il s'agit
d'un moteur de base de données petit et éprouvé. Le package sqflite fournit de nombreuses fonctionnalités pour
travailler efficacement avec la base de données SQLite. Il fournit des méthodes standard pour manipuler le moteur
de base de données SQLite. Les fonctionnalités principales fournies par le package sqflite sont les suivantes :
• Méthodes de requête avancées (méthode de requête) pour réduire le code requis pour interroger et
obtenir des informations de la base de données SQLite.
Créons une application produit pour stocker et récupérer des informations produit à partir d'un moteur de base de
données SQLite standard à l'aide du package sqflite et comprenons le concept derrière la base de données SQLite
et le package sqflite.
• Remplacez le code de démarrage par défaut (main.dart) par notre code product_rest_app .
battement:
actifs:
assets/appimages/floppy.png
assets/appimages/iphone.png
assets/appimages/ordinateur portable.png
assets/appimages/clé usb.png
assets/appimages/pixel.png
assets/appimages/tablette.png
dépendances:
sqflite : tout
125
Machine Translated by Google
Battement
dépendances :
path_provider : any
• Ici, le package path_provider est utilisé pour obtenir le chemin du dossier temporaire du système et le
chemin de l'application. Utilisez le dernier numéro de version de sqflite à la place de n'importe quel autre.
• Cliquez sur l'option Obtenir les dépendances. Android Studio récupérera le package sur Internet et le
configurera correctement pour l'application.
• Dans la base de données, nous avons besoin d'une clé primaire, d'un identifiant comme champ supplémentaire
ainsi que des propriétés du produit telles que le nom, le prix, etc. Ajoutez donc la propriété id dans la classe
Product. Ajoutez également une nouvelle méthode, toMap, pour convertir l'objet produit en objet Map. fromMap
et toMap sont utilisés pour sérialiser et désérialiser l'objet Product et sont utilisés dans les méthodes de
manipulation de base de données.
données['description'],
données['prix'],
données['image'], );
• Créez un nouveau fichier, Database.dart dans le dossier lib pour écrire les fonctionnalités liées à SQLite .
126
Machine Translated by Google
Battement
importer 'dart:async';
importer 'dart:io';
importer 'package:path/path.dart';
importer 'Produit.dart';
• path est utilisé pour accéder à la fonction utilitaire principale de Dart liée aux chemins de fichiers.
• Déclarez un objet SQLiteDbProvider statique basé sur un singleton comme spécifié cidessous :
classe SQLiteDbProvider
{ SQLiteDbProvider._();
SQLiteDBProvoider.db.<méthode>
• Créez une méthode pour obtenir la base de données (option Future) de type Future<Database>.
Créez une table de produits et chargez les données initiales lors de la création de la base de données ellemême.
initDB() asynchrone {
Répertoire documentsDirectory = wait
getApplicationDocumentsDirectory(); String path
= join(documentsDirectory.path, "ProductDB.db"); return wait openDatabase( path,
version: 1,
127
Machine Translated by Google
Battement
attendre db.execute(
"INSÉRER DANS le produit ('id', 'nom', 'description', 'prix',
valeurs 'image') (?, ?, ?, ?, ?)",
[1, "iPhone", "iPhone est le téléphone le plus stylé de tous les temps", 1000,
"iphone.png"]);
attendre db.execute(
"INSÉRER DANS le produit ('id', 'nom', 'description', 'prix',
valeurs 'image') (?, ?, ?, ?, ?)",
[2, « Pixel », « Pixel est le téléphone le plus complet jamais conçu », 800,
"pixel.png"]);
attendre db.execute(
"INSÉRER DANS le produit ('id', 'nom', 'description', 'prix',
valeurs 'image') (?, ?, ?, ?, ?)",
[3, « Ordinateur portable », « L'ordinateur portable est l'outil de développement le plus productif »,
2000, "ordinateur portable.png"]);
attendre db.execute(
"INSÉRER DANS le produit ('id', 'nom', 'description', 'prix',
valeurs 'image') (?, ?, ?, ?, ?)",
[4, « Tablette », « L’ordinateur portable est l’outil de développement le plus productif »,
1500, "tablette.png"]);
attendre db.execute(
"INSÉRER DANS le produit ('id', 'nom', 'description', 'prix',
valeurs 'image') (?, ?, ?, ?, ?)",
[5, "Pendrive", "Pendrive est un support de stockage utile", 100, "pendrive.png"]);
attendre db.execute(
"INSÉRER DANS le produit ('id', 'nom', 'description', 'prix',
valeurs 'image') (?, ?, ?, ?, ?)",
[6, « Lecteur de disquette », « Le lecteur de disquette est un support de stockage
de secours utile », 20, « floppy.png »]);
});
}
• join Utilisé pour créer un chemin spécifique au système. Nous l'avons utilisé pour créer une base de données
chemin.
128
Machine Translated by Google
Battement
• onOpen Utilisé pour écrire du code lors de l'ouverture d'une base de données
• onCreate Utilisé pour écrire du code lorsqu'une base de données est créée pour la première fois
• db.execute Utilisé pour exécuter des requêtes SQL. Il accepte une requête. Si la requête a
espace réservé (?), puis il accepte les valeurs sous forme de liste dans le deuxième argument.
• Écrivez une méthode pour obtenir tous les produits de la base de données :
• Méthode de requête utilisée pour récupérer toutes les informations sur le produit. La requête fournit un raccourci
pour interroger les informations d'une table sans écrire la requête entière. La méthode de requête générera
ellemême la requête appropriée en utilisant nos entrées telles que les colonnes, orderBy, etc.
• Méthode fromMap du produit utilisé pour obtenir les détails du produit en bouclant les résultats
objet, qui contient toutes les lignes de la table.
• Ici, nous avons utilisé where et whereArgs pour appliquer des filtres.
• Créez trois méthodes : insérer, mettre à jour et supprimer pour insérer, mettre à jour et supprimer le produit de la
base de données
129
Machine Translated by Google
Battement
var id = maxIdResult.first["dernier_id_inséré"];
retourner le résultat;
}
retourner le résultat;
}
importer 'dart:async';
importer 'dart:io'; importer
'package:path/path.dart';
importer 'Produit.dart';
classe SQLiteDbProvider
{ SQLiteDbProvider._();
initDB() asynchrone {
130
Machine Translated by Google
Battement
attendre db.execute(
"INSÉRER DANS le produit ('id', 'nom', 'description', 'prix',
valeurs 'image') (?, ?, ?, ?, ?)",
[1, "iPhone", "iPhone est le téléphone le plus stylé de tous les temps", 1000,
"iphone.png"]);
attendre db.execute(
"INSÉRER DANS le produit ('id', 'nom', 'description', 'prix',
valeurs 'image') (?, ?, ?, ?, ?)",
[2, « Pixel », « Pixel est le téléphone le plus complet jamais conçu », 800,
"pixel.png"]);
attendre db.execute(
"INSÉRER DANS le produit ('id', 'nom', 'description', 'prix',
valeurs 'image') (?, ?, ?, ?, ?)",
[3, « Ordinateur portable », « L'ordinateur portable est l'outil de développement le plus productif »,
2000, "ordinateur portable.png"]);
attendre db.execute(
"INSÉRER DANS le produit ('id', 'nom', 'description', 'prix',
valeurs 'image') (?, ?, ?, ?, ?)",
[4, « Tablette », « L’ordinateur portable est l’outil de développement le plus productif »,
1500, "tablette.png"]);
attendre db.execute(
"INSÉRER DANS le produit ('id', 'nom', 'description', 'prix',
valeurs 'image') (?, ?, ?, ?, ?)",
[5, "Pendrive", "Pendrive est un support de stockage utile", 100, "pendrive.png"]);
attendre db.execute(
"INSÉRER DANS le produit ('id', 'nom', 'description', 'prix',
valeurs 'image') (?, ?, ?, ?, ?)",
[6, « Lecteur de disquette », « Le lecteur de disquette est un support de stockage
de secours utile », 20, « floppy.png »]);
});
}
131
Machine Translated by Google
Battement
retourner le résultat;
}
retourner le résultat;
}
132
Machine Translated by Google
Battement
}
}
vide main() {
runApp(MyApp(produits : SQLiteDbProvider.db.getAllProducts()));
}
• Ici, nous avons utilisé la méthode getAllProducts pour récupérer tous les produits de la base de données.
• Exécutez l'application et observez les résultats. Elle sera similaire à l'exemple précédent, Accès à l'API du service Produit,
sauf que les informations sur le produit sont stockées et extraites de la base de données SQLite locale.
Firebase est une plateforme de développement d'applications BaaS. Elle propose de nombreuses fonctionnalités pour
accélérer le développement d'applications mobiles, comme le service d'authentification, le stockage dans le cloud, etc. L'une
des principales fonctionnalités de Firebase est Cloud Firestore, une base de données NoSQL en temps réel basée sur le cloud.
Flutter fournit un package spécial, cloud_firestore, pour programmer avec Cloud Firestore. Créons une boutique de produits
en ligne dans Cloud Firestore et créons une application pour accéder à la boutique de produits.
• Remplacez le code de démarrage par défaut (main.dart) par notre code product_rest_app .
classe Produit {
nom de chaîne final ;
description finale de la chaîne ;
prix int final;
image de chaîne finale ;
• Copiez le dossier assets de product_rest_app vers product_firebase_app et ajoutez les assets dans le fichier
pubspec.yaml
battement:
133
Machine Translated by Google
Battement
actifs:
assets/appimages/floppy.png
assets/appimages/iphone.png
assets/appimages/ordinateur portable.png
assets/appimages/clé usb.png
assets/appimages/pixel.png
assets/appimages/tablette.png
dépendances:
cloud_firestore : ^0.9.13+1
• Android Studio avertira que le fichier pubspec.yaml est mis à jour comme indiqué ici :
• Cliquez sur l'option Obtenir les dépendances. Android Studio récupérera le package sur Internet et le
configurera correctement pour l'application.
• Une fois le compte Firebase créé, il sera redirigé vers la page de présentation du projet. Elle répertorie tous les
projets basés sur Firebase et offre une option pour créer un nouveau projet.
• Saisissez la base de données de l’application des produits comme nom de projet et cliquez sur l’option Créer un projet.
• Cliquez sur l'icône Android. Cela ouvrira les paramètres du projet spécifiques au développement Android.
• Cliquez sur Enregistrer l'application. Cela génère un fichier de configuration de projet, google_service.json
• Téléchargez google_service.json puis déplacezle dans le répertoire android/app du projet. Ce fichier constitue
la connexion entre notre application et Firebase.
134
Machine Translated by Google
Battement
buildscript
{ référentiels { // ...
dépendances { // ...
classpath
'com.google.gms:googleservices:3.2.1' // nouveau
}
}
Ici, le plugin et le chemin de classe sont utilisés pour lire le fichier google_service.json.
android
{config par défaut {
...
multiDexEnabled vrai
}
...
}
dépendances {
...
compiler 'com.android.support: multidex:1.0.3'
}
• Créez un magasin de produits dans le projet nouvellement créé en suivant les étapes suivantes :
• Cliquez sur Ajouter une collection. Saisissez le produit comme nom de collection, puis cliquez sur Suivant.
• Saisissez les informations sur l'exemple de produit comme indiqué dans l'image ici :
135
Machine Translated by Google
Battement
• Ajoutez des informations supplémentaires sur le produit à l’aide des options Ajouter un document .
• Ouvrez le fichier main.dart et importez le fichier du plugin Cloud Firestore et supprimez le package http.
importer 'package:cloud_firestore/cloud_firestore.dart';
• Supprimez parseProducts et mettez à jour fetchProducts pour récupérer les produits depuis le Cloud
Firestore au lieu de l'API du service produit
Flux<QuerySnapshot> fetchProducts() {
renvoie Firestore.instance.collection('produit').snapshots();
}
• Ici, la méthode Firestore.instance.collection est utilisée pour accéder à la collection de produits disponible
dans le magasin cloud. Firestore.instance.collection fournit de nombreuses options pour filtrer la collection afin
d'obtenir les documents nécessaires. Cependant, nous n'avons appliqué aucun filtre pour obtenir toutes les
informations sur les produits.
• Cloud Firestore fournit la collection via le concept Dart Stream et modifie ainsi le type de produits dans le widget MyApp
et MyHomePage de Future<list<Product>> à Stream<QuerySnapshot>.
136
Machine Translated by Google
Battement
@outrepasser
Création de widget (contexte de BuildContext)
{ return Scaffold
(appBar : AppBar (titre : Texte (« Navigation du produit »)), body :
Center (enfant :
StreamBuilder <QuerySnapshot> (stream : produits,
builder : (contexte,
instantané) {
si (snapshot.hasError) print(snapshot.error);
if(snapshot.hasData)
{ Liste<DocumentSnapshot> documents = snapshot.data.documents; Liste<Produit>
éléments = Liste<Produit>();
éléments.add(Product.fromMap(document.data));
}
} }, ), ));
}
• Ici, nous avons récupéré les informations sur le produit sous forme de type List<DocumentSnapshot>.
Étant donné que notre widget, ProductBoxList, n'est pas compatible avec les documents, nous avons converti
les documents en type List<Product> et les avons utilisés ultérieurement.
• Enfin, exécutez l'application et observez le résultat. Étant donné que nous avons utilisé les mêmes informations
produit que celles de l'application SQLite et modifié uniquement le support de stockage, l'application résultante
ressemble à l'application SQLite .
137
Machine Translated by Google
De nos jours, les applications mobiles sont utilisées par des clients de différents pays et, par conséquent,
elles doivent afficher le contenu dans différentes langues. Permettre à une application de fonctionner dans
plusieurs langues s'appelle l'internationalisation de l'application.
Pour qu'une application fonctionne dans différentes langues, elle doit d'abord trouver les paramètres
régionaux actuels du système dans lequel l'application s'exécute, puis afficher son contenu dans ces
paramètres régionaux particuliers, et ce processus est appelé localisation.
Le framework Flutter fournit trois classes de base pour la localisation et des classes utilitaires étendues
dérivées des classes de base pour localiser une application.
• Paramètres régionaux : les paramètres régionaux sont une classe utilisée pour identifier la langue de l'utilisateur. Par exemple, enus
identifie l'anglais américain et peut être créé comme :
Ici, le premier argument est le code de langue et le deuxième argument est le code du pays.
Voici un autre exemple de création de paramètres régionaux en espagnol argentin (esar) :
• Localisations Les localisations sont un widget générique utilisé pour définir les paramètres régionaux et les
ressources localisées de son enfant.
classe CustomLocalizations {
CustomLocalisations(this.locale);
138
Machine Translated by Google
Battement
• Ici, CustomLocalizations est une nouvelle classe personnalisée créée spécifiquement pour obtenir certains contenus
localisés (titre et message) pour le widget. La méthode of utilise la classe Localizations pour renvoyer la nouvelle
classe CustomLocalizations.
• LocalizationsDelegate<T> LocalizationsDelegate<T> est une classe d'usine via laquelle le widget Localizations est chargé.
Elle possède trois méthodes remplaçables :
@outrepasser
bool isSupported(Locale locale) => ['en',
'es'].contains(locale.languageCode);
• load Accepte des paramètres régionaux et commence à charger les ressources pour les paramètres régionaux
spécifiés.
@outrepasser
Future<CustomLocalizations> load(Paramètres régionaux locaux) {
retour
SynchronousFuture<CustomLocalizations>(CustomLocalizations(locale));
}
Ici, la méthode load renvoie CustomLocalizations. Les CustomLocalizations renvoyées peuvent être utilisées
pour obtenir les valeurs du titre et du message en anglais et en espagnol.
• shouldReload Spécifie si le rechargement de CustomLocalizations est nécessaire lorsque son widget Localisations
est reconstruit.
@outrepasser
bool shouldReload(CustomLocalizationsDelegate ancien) => faux;
@outrepasser
bool isSupported(Locale locale) => ['en',
'es'].contient(locale.languageCode);
@outrepasser
Future<CustomLocalizations> load(Locale locale) {
retour
SynchronousFuture<CustomLocalizations>(CustomLocalizations(locale));
139
Machine Translated by Google
Battement
@outrepasser
bool shouldReload(CustomLocalizationsDelegate ancien) => faux;
}
En général, les applications Flutter sont basées sur deux widgets de niveau racine, MaterialApp ou WidgetsApp. Flutter fournit
une localisation prête à l'emploi pour les deux widgets : MaterialLocalizations et WidgetsLocaliations. De plus, Flutter fournit
également des délégués pour charger respectivement MaterialLocalizations et GlobalMaterialLocalizations.delegate.
WidgetsLocaliations et eux et sont
GlobalWidgetsLocalizations.delegate
Créons une application simple compatible avec l’internationalisation pour tester et comprendre le concept.
• Flutter prend en charge l'internationalisation à l'aide du package exclusif Flutter, flutter_localizations. L'idée est de
séparer le contenu localisé du SDK principal.
Ouvrez le fichier pubspec.yaml et ajoutez le code cidessous pour activer le package d'internationalisation :
dépendances:
battement:
SDK : Flutter
flutter_localisations :
SDK : Flutter
• Android Studio affichera l'alerte suivante indiquant que pubspec.yaml est mis à jour.
• Cliquez sur l'option Obtenir les dépendances. Android Studio récupérera le package sur Internet et le configurera
correctement pour l'application.
importer 'package:flutter_localizations/flutter_localizations.dart';
importer 'package:flutter/foundation.dart' afficher SynchronousFuture;
• Ici, le but de SynchronousFuture est de charger les localisations personnalisées de manière synchrone.
• Créez une localisation personnalisée et son délégué correspondant comme spécifié cidessous :
classe CustomLocalizations {
CustomLocalisations(this.locale);
140
Machine Translated by Google
Battement
}, };
@override
bool isSupported(Locale locale) => ['en',
'es'].contient(locale.languageCode);
@outrepasser
Future<CustomLocalizations> load(Paramètres régionaux locaux) {
retour
SynchronousFuture<CustomLocalizations>(CustomLocalizations(locale));
}
@override
bool shouldReload(CustomLocalizationsDelegate ancien) => faux;
}
• Ici, CustomLocalizations est créé pour prendre en charge la localisation du titre et du message dans
l'application et CustomLocalizationsDelegate est utilisé pour charger CustomLocalizations.
• Ajoutez des délégués pour MaterialApp, WidgetsApp et CustomLocalization à l'aide des propriétés MaterialApp,
localizationsDelegates et supportedLocales comme spécifié cidessous :
141
Machine Translated by Google
Battement
@outrepasser
Création de widget (contexte BuildContext) {
retourner l'échafaudage(
Barre d'application : Barre d'application (
• Ici, nous avons modifié la classe MyHomePage de StatefulWidget à StatelessWidget pour des raisons
de simplicité et utilisé CustomLocalizations pour obtenir le titre et le message.
• Fermez l'application. Allez dans Paramètres > Système > Langues et saisie >
Langues*
• Cliquez sur Ajouter une option de langue et sélectionnez l'espagnol. Cela installera la langue espagnole
et la listera comme l'une des options.
• Sélectionnez l'espagnol et déplacezle audessus de l'anglais. L'espagnol sera alors défini comme
première langue et tout sera converti en texte espagnol.
• Nous pouvons rétablir la langue en anglais en déplaçant l'option anglaise audessus de l'espagnol
option dans le paramètre.
• Le résultat de l'application (en espagnol) est affiché dans la capture d'écran cidessous :
142
Machine Translated by Google
Battement
Flutter fournit un package intl pour simplifier davantage le développement d'applications mobiles localisées. Le package intl fournit des
méthodes et des outils spéciaux pour générer semiautomatiquement des messages spécifiques à la langue.
Créons une nouvelle application localisée en utilisant le package intl et comprenons le concept.
dépendances : flutter :
SDK : Flutter
flutter_localizations : sdk : flutter
intl : ^0,15,7
intl_translation : ^0,17,3
143
Machine Translated by Google
Battement
• Android Studio affichera l'alerte comme indiqué cidessous informant que le fichier pubspec.yaml
est mis à jour.
• Cliquez sur l'option Obtenir les dépendances. Android Studio récupérera le package sur Internet et le
configurera correctement pour l'application.
importer 'package:intl/intl.dart';
classe CustomLocalizations {
statique Future<CustomLocalizations> load(Locale locale) {
nom de chaîne final = locale.countryCode.isEmpty ? locale.languageCode : locale.toString(); nom
de chaîne final
localeName = Intl.canonicalizedLocale(nom);
renvoie initializeMessages(localeName).then((_) {
Intl.defaultLocale = localeName; return
CustomLocalizations(); });
}
}
@outrepasser
144
Machine Translated by Google
Battement
@outrepasser
Future<CustomLocalizations> load(Paramètres régionaux locaux) {
renvoyer CustomLocalizations.load(locale);
}
@outrepasser
bool shouldReload(CustomLocalizationsDelegate ancien) => faux;
}
• Ici, nous avons utilisé trois méthodes du package intl au lieu de méthodes personnalisées.
Sinon, les concepts sont les mêmes.
importer 'l10n/messages_all.dart';
• Ouvrez une invite de commande et accédez au répertoire racine de l'application (où pubspec.yaml
est disponible) et exécutez la commande suivante :
• Ici, la commande va générer le fichier intl_message.arb, un modèle pour créer un message dans différentes
langues. Le contenu du fichier est le suivant :
{
"@@last_modified": "20190419T02:04:09.627551",
"titre": "Démo",
"@titre": {
"description": "Titre de l'application de démonstration",
"type": "texte",
« espaces réservés » : {}
},
"message": "Bonjour tout le monde",
"@message": {
"description": "Message pour l'application de démonstration",
"type": "texte",
« espaces réservés » : {}
}
}
• Copiez intl_message.arb et créez un nouveau fichier, intl_es.arb et modifiez le contenu en espagnol comme
indiqué cidessous :
145
Machine Translated by Google
Battement
{
"@@last_modified": "20190419T02:04:09.627551", "title":
"Manifestation", "@title":
{ "description":
"Titre de l'application de démonstration", "type": "text",
"placeholders": {} },
"message": "Hola
Mundo", "@message": {
• Maintenant, exécutez la commande suivante pour créer le fichier de message final, messages_all.dart
146
Machine Translated by Google
Les tests constituent une phase très importante du cycle de développement d'une application. Ils garantissent la qualité
de l'application. Les tests nécessitent une planification et une exécution minutieuses. C'est également la phase la plus
chronophage du développement.
Le langage Dart et le framework Flutter offrent un support étendu pour les tests automatisés d'une application.
Types de tests
Généralement, trois types de processus de test sont disponibles pour tester complètement une application.
Ils sont les suivants :
Tests unitaires
Les tests unitaires sont la méthode la plus simple pour tester une application. Ils visent à garantir l'exactitude d'un
morceau de code (une fonction, en général) ou d'une méthode d'une classe. Mais ils ne reflètent pas l'environnement
réel et constituent donc la moindre option pour détecter les bugs.
Tests d'intégration
Les tests d'intégration impliquent à la fois des tests unitaires et des tests de widgets ainsi que des composants externes
de l'application comme une base de données, un service Web, etc. Il simule ou simule l'environnement réel pour trouver
presque tous les bugs, mais c'est le processus le plus compliqué.
Flutter prend en charge tous les types de tests. Il fournit un support complet et exclusif pour les tests de widgets. Dans
ce chapitre, nous aborderons en détail les tests de widgets.
• Description du test
• Code de test
147
Machine Translated by Google
Battement
Étapes impliquées
Les tests de widgets impliquent trois étapes distinctes :
• WidgetTester est la classe fournie par le framework de test Flutter pour créer et restituer le widget. La
méthode pumpWidget de la classe WidgetTester accepte n'importe quel widget et le restitue dans
l'environnement de test.
• Le framework Flutter propose de nombreuses options pour trouver les widgets affichés dans
l'environnement de test et elles sont généralement appelées Finders. Les finders les plus
fréquemment utilisés sont find.text, find.byKey et find.byWidget
• find.text trouve le widget qui contient le texte spécifié.
find.text('Bonjour')
trouver.byKey('accueil')
trouver.byWidget(homeWidget)
• Le framework Flutter propose de nombreuses options pour faire correspondre le widget avec le
widget attendu et elles sont normalement appelées Matchers. Nous pouvons utiliser la méthode
expect fournie par le framework de test pour faire correspondre le widget, que nous avons trouvé à la
deuxième étape avec notre widget attendu en choisissant l'un des matchers. Certains des matchers
importants sont les suivants :
expect(find.text('Bonjour'), findsOneWidget);
148
Machine Translated by Google
Battement
expect(find.text('Enregistrer'), findsWidgets);
expect(find.text('Enregistrer'), findsNWidgets(2));
expect(find.text('Bonjour'), findsOneWidget);
});
Ici, nous avons rendu un widget MaterialApp avec le texte Hello en utilisant le widget Texte dans son corps.
Ensuite, nous avons utilisé find.text pour trouver le widget, puis nous l'avons associé à findsOneWidget.
Exemple de travail
Créons une application Flutter simple et écrivons un test de widget pour mieux comprendre les étapes
impliquées et le concept.
• Ouvrez widget_test.dart dans le dossier test. Il contient un exemple de code de test comme indiqué cidessous :
149
Machine Translated by Google
Battement
• Appuyez à nouveau sur le bouton d'incrémentation du compteur, puis vérifiez si le compteur est augmenté à deux.
attendre tester.tap(find.byIcon(Icons.add));
attendre tester.pump();
expect(find.text('2'), trouveUnWidget);
• Cliquez sur Tests dans l'option widget_test.dart. Cela exécutera le test et affichera le résultat dans la fenêtre de
résultats.
150
Machine Translated by Google
Ce chapitre explique comment déployer l'application Flutter sur les platesformes Android et iOS.
Application Android
• Modifiez le nom de l’application à l’aide de l’entrée android:label dans le fichier manifeste Android.
Le fichier manifeste de l'application Android, AndroidManifest.xml, se trouve dans <app dir>/android/app/src/
main. Il contient tous les détails d'une application Android.
Nous pouvons définir le nom de l'application à l'aide de l'entrée android:label.
cd /chemin/vers/mon/application
apk de construction de flutter
installation de flutter
• Publiez l'application sur Google Playstore en créant un appbundle et envoyezla dans Playstore à l'aide de
méthodes standard.
Application iOS
• Enregistrez l'application iOS dans App Store Connect à l'aide de la méthode standard. Enregistrez l' ID de
bundle utilisé lors de l'enregistrement de l'application.
• Mettez à jour le nom d’affichage dans les paramètres du projet XCode pour définir le nom de l’application.
151
Machine Translated by Google
Battement
• Mettez à jour l'identifiant du bundle dans les paramètres du projet XCode pour définir l'ID du bundle, que nous
utilisé à l'étape 1.
• Testez l'application en poussant l'application, le fichier IPA dans TestFlight à l'aide de la méthode standard.
152
Machine Translated by Google
Ce chapitre explique en détail les outils de développement Flutter. La première version stable de la boîte à outils de
développement multiplateforme est sortie le 4 décembre 2018, Flutter 1.0.
Eh bien, Google travaille continuellement sur les améliorations et le renforcement du framework Flutter avec différents
outils de développement.
Ensembles de widgets
Google a mis à jour les ensembles de widgets Material et Cupertino pour offrir une qualité au pixel près dans la conception
des composants. La prochaine version de Flutter 1.2 sera conçue pour prendre en charge les événements du clavier du
bureau et le survol de la souris.
Visual Studio Code prend en charge le développement Flutter et fournit de nombreux raccourcis pour un développement
rapide et efficace. Certaines des fonctionnalités clés fournies par Visual Studio Code pour le développement Flutter sont
répertoriées cidessous :
• Assistance de code Lorsque vous souhaitez vérifier les options, vous pouvez utiliser Ctrl+Espace pour obtenir un
liste des options de complétion de code.
• Correction rapide Ctrl+. est un outil de correction rapide pour aider à corriger le code.
• Raccourcis de débogage.
• Redémarrages à chaud
Nous pouvons utiliser Android Studio ou Visual Studio Code, ou tout autre IDE pour écrire notre code et installer des
plugins. L'équipe de développement de Google a travaillé sur un autre outil de développement appelé Dart DevTools. Il
s'agit d'une suite de programmation Web. Il prend en charge les platesformes Android et iOS. Il est basé sur une vue
chronologique afin que les développeurs puissent facilement analyser leurs applications.
Installer DevTools
Pour installer DevTools, exécutez la commande suivante dans votre console :
153
Machine Translated by Google
Battement
+ charcode 1.1.2 +
codemirror 0.5.3+5.44.0
+ collection 1.14.11
+ convertir 2.1.1 + outils
de développement 0.0.16
+ js 0.6.1+1 + méta
1.1.7
+ mime 0.9.6+2
..................
..................
Exécuter le serveur
http://localhost:9100/?port=9200
154
Machine Translated by Google
Battement
Inspecteur Flutter
Il est utilisé pour explorer les arborescences de widgets Flutter. Pour ce faire, exécutez la commande cidessous dans
votre console,
155
Machine Translated by Google
Battement
Pour recharger à chaud les modifications pendant l'exécution, appuyez sur « r ». Pour redémarrer à chaud (et reconstruire
l'état), appuyez sur « R ».
Un débogueur et profileur Observatory sur iPhone X est disponible à l'adresse suivante : http://
127.0.0.1:50399/
Pour un message d'aide plus détaillé, appuyez sur « h ». Pour vous déconnecter, appuyez sur « d » ; pour quitter, appuyez
sur « q ».
156
Machine Translated by Google
Dans ce chapitre, nous allons apprendre à écrire une application mobile complète, expenses_calculator. Le but de
expenses_calculator est de stocker nos informations de dépenses. Les fonctionnalités complètes de l'application sont
les suivantes :
Nous allons programmer l'application expenses_calculator en utilisant les fonctionnalités avancées mentionnées cidessous
du framework Flutter.
• Programmation de formulaires
dépendances : flutter :
SDK : Flutter
sqflite : ^1.1.0
path_provider : ^0.5.0+1
scoped_model : ^1.0.1 intl :
tout
SQLite. • path_provider est utilisé pour obtenir le chemin d'application spécifique au système.
• Android Studio affichera l'alerte suivante indiquant que pubspec.yaml est mis à jour.
• Cliquez sur l'option Obtenir les dépendances. Android Studio récupérera le package sur Internet et le configurera
correctement pour l'application.
157
Machine Translated by Google
Battement
• Ajoutez un nouveau fichier, Expense.dart pour créer la classe Expense. La classe Expense aura les propriétés et
méthodes cidessous.
• propriété : id ID unique pour représenter une entrée de dépense dans la base de données SQLite.
• propriété : catégorie La catégorie représente le domaine dans lequel le montant est dépensé.
• fromMap Utilisé pour mapper le champ de la table de base de données à la propriété dans le
DateTime.parse(data['date']),
data['category']
);
}
• toMap Utilisé pour convertir l'objet de dépenses en Dart Map, qui peut être utilisé ultérieurement dans
la programmation de base de données
importer 'package:intl/intl.dart';
classe Dépense
{ final int id; final
double montant; final
DateTime date; final String
catégorie;
158
Machine Translated by Google
Battement
DateTime.parse(données['date']),
données['catégorie'] );
• Ajoutez un nouveau fichier, Database.dart pour créer la classe SQLiteDbProvider. L'objectif de la classe
SQLiteDbProvider est le suivant :
• Obtenez toutes les dépenses disponibles dans la base de données à l'aide de la méthode getAllExpenses.
sera utilisé pour lister toutes les informations de dépenses de l'utilisateur.
frais de retour;
}
• Obtenir des informations de dépenses spécifiques en fonction de l'identité des dépenses disponibles dans
la base de données à l'aide de la méthode getExpenseById. Elle sera utilisée pour afficher les
informations de dépenses particulières à l'utilisateur.
159
Machine Translated by Google
Battement
• Ajoutez de nouvelles informations sur les dépenses dans la base de données à l'aide de la méthode d'insertion. Cela
être utilisé pour ajouter une nouvelle entrée de dépenses dans l'application par l'utilisateur.
);
• Mettre à jour les informations de dépenses existantes à l'aide de la méthode de mise à jour. Elle sera utilisée
pour modifier et mettre à jour les entrées de dépenses existantes disponibles dans le système par l'utilisateur.
retourner le résultat;
}
• Supprimez les informations de dépenses existantes à l'aide de la méthode de suppression. Elle permettra de
supprimer l'entrée de dépenses existante disponible dans le système par l'utilisateur.
160
Machine Translated by Google
Battement
importer 'Expense.dart';
classe SQLiteDbProvider
{ SQLiteDbProvider._();
initDB() asynchrone {
Répertoire documentsDirectory = wait getApplicationDocumentsDirectory(); String path =
join(documentsDirectory.path, "ExpenseDB2.db"); return wait openDatabase( path, version:
1, onOpen: (db) {}, onCreate:
(Database db,
int version) async {
161
Machine Translated by Google
Battement
"pixel.png"]);
attendre db.execute(
"INSÉRER DANS le produit ('id', 'nom', 'description', 'prix',
valeurs 'image') (?, ?, ?, ?, ?)",
[3, « Ordinateur portable », « L'ordinateur portable est l'outil de développement le plus productif »,
2000, « laptop.png »]);
attendre db.execute(
"INSÉRER DANS le produit ('id', 'nom', 'description', 'prix',
valeurs 'image') (?, ?, ?, ?, ?)",
[4, « Tablette », « L'ordinateur portable est l'outil de développement le plus productif »,
1500, « tablette.png »]);
attendre db.execute(
"INSÉRER DANS le produit ('id', 'nom', 'description', 'prix',
valeurs 'image') (?, ?, ?, ?, ?)",
[5, « Pendrive », « L'iPhone est le téléphone le plus stylé de tous les temps », 100,
"clé USB.png"]);
attendre db.execute(
"INSÉRER DANS le produit ('id', 'nom', 'description', 'prix',
valeurs 'image') (?, ?, ?, ?, ?)",
[6, « Lecteur de disquette », « L'iPhone est le téléphone le plus stylé de tous les
temps », 20, « floppy.png »]);
*/
});
}
frais de retour;
}
162
Machine Translated by Google
Battement
var id = maxIdResult.first["dernier_id_inséré"];
retourner le résultat;
}
• Ici,
• Créez un nouveau fichier, ExpenseListModel.dart pour créer ExpenseListModel. Le but du modèle est de conserver les
informations complètes sur les dépenses de l'utilisateur dans la mémoire et de mettre à jour l'interface utilisateur de
l'application chaque fois que les dépenses de l'utilisateur changent dans la mémoire. Il est basé sur la classe Model
du package scoped_model. Il possède les propriétés et méthodes suivantes :
• items getter pour _items comme UnmodifiableListView<Expense> pour éviter les modifications
inattendues ou accidentelles de la liste.
• totalExpense getter pour les dépenses totales en fonction de la variable des éléments.
163
Machine Translated by Google
Battement
montant du retour;
}
• load Utilisé pour charger les dépenses complètes depuis la base de données et dans la variable _items.
Il appelle également notifyListeners pour mettre à jour l'interface utilisateur.
void load()
{ Future<Liste<Dépense>> list = SQLiteDbProvider.db.getAllExpenses();
notifierListeners(); });
• byId Utilisé pour obtenir une dépense particulière à partir de la variable _items.
}
}
retourner null;
}
• add Utilisé pour ajouter un nouvel élément de dépense dans la variable _items ainsi que dans la base
de données. Il appelle également notifyListeners pour mettre à jour l'interface utilisateur.
notifierListeners(); });
• add Utilisé pour ajouter un nouvel élément de dépense dans la variable _items ainsi que dans la base de
données. Il appelle également notifyListeners pour mettre à jour l'interface utilisateur.
164
Machine Translated by Google
Battement
SQLiteDbProvider.db.update(item); break;
}
}
si(trouvé) notifyListeners();
}
• supprimer Utilisé pour supprimer un élément de dépense existant dans la variable _items ainsi que
à partir de la base de données. Il appelle également notifyListeners pour mettre à jour l'interface utilisateur.
SQLiteDbProvider.db.delete(item.id);
_items.removeAt(i); break;
}
}
si(trouvé) notifyListeners();
}
ExpenseListModel() { this.load(); }
165
Machine Translated by Google
Battement
montant du retour;
}
void load()
{ Future<Liste<Dépense>> list =
SQLiteDbProvider.db.getAllExpenses();
notifierListeners(); });
}
}
retourner null;
}
notifierListeners(); });
SQLiteDbProvider.db.update(item); break;
}
}
si(trouvé) notifyListeners();
}
166
Machine Translated by Google
Battement
SQLiteDbProvider.db.delete(item.id);
_items.removeAt(i); break;
}
}
si(trouvé) notifyListeners();
}
}
importer 'Expense.dart';
void main()
{ dépenses finales = ExpenseListModel();
runApp(ScopedModel<ExpenseListModel>( modèle :
dépenses, enfant :
MyApp(), ));
• Ici,
• L'objet dépenses charge toutes les informations sur les dépenses des utilisateurs à partir de la base de données.
De plus, lorsque l'application est ouverte pour la première fois, elle crée la base de
données requise avec les tables appropriées.
• ScopedModel fournit les informations sur les dépenses tout au long du cycle de vie de l'application et
assure la maintenance de l'état de l'application à tout moment. Il nous permet d'utiliser
StatelessWidget au lieu de StatefulWidget.
build(BuildContext context) {
renvoyer MaterialApp( titre :
'Dépenses', thème :
ThemeData(
167
Machine Translated by Google
Battement
}
}
• Créez un widget MyHomePage pour afficher toutes les informations sur les dépenses de l'utilisateur ainsi que les
dépenses totales en haut. Le bouton flottant dans le coin inférieur droit sera utilisé pour ajouter de nouvelles
dépenses.
@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar( title:
Texte(this.title), ), corps:
); } else
{ index = index 1; return
Dismissible( clé :
Key(expenses.items[index].id.toString()), onDismissed : (direction)
{
dépenses.delete(dépenses.éléments[index]);
Scaffold.of(context).showSnackBar(SnackBar( contenu :
Texte("Article avec identifiant, " +
expenses.items[index].id.toString()
+
" est rejeté")));
},
enfant : ListTile( onTap :
()
{ Navigator.push( contexte,
MaterialPageRoute( constructeur :
(contexte) => FormPage( id :
dépenses.éléments[index].id,
168
Machine Translated by Google
Battement
},
en tête : Icône(Icons.monetization_on), en queue :
Icône(Icons.keyboard_arrow_right),
titre : Texte(dépenses.éléments[index].catégorie
+
": " +
ScopedModelDescendant<ExpenseListModel>( builder:
(contexte, enfant, dépenses) { return
FloatingActionButton( onPressed: () {
Navigator.push( contexte,
MaterialPageRoute( constructeur :
(contexte) => ScopedModelDescendant<ExpenseListModel>(
constructeur : (contexte, enfant, dépenses) { return
FormPage( id : 0,
« Incrément », enfant :
icône(Icons.add), ); }));
}
}
• Ici,
169
Machine Translated by Google
Battement
• Le widget ListView.separated et ListTile est utilisé pour répertorier les informations sur les dépenses.
• Le widget pouvant être supprimé est utilisé pour supprimer l'entrée de dépenses à l'aide d'un geste de balayage.
• Le navigateur permet d'ouvrir l'interface d'édition d'une entrée de dépense. Il peut être activé par
en appuyant sur une entrée de dépense.
• Créez un widget FormPage. Le widget FormPage a pour but d'ajouter ou de mettre à jour une entrée de
dépenses. Il gère également la validation des entrées de dépenses.
@outrepasser
_FormPageState createState() => _FormPageState(id: id, dépenses: dépenses); }
double _montant;
DateHeure _date;
Chaîne _category;
vide _submit() {
forme finale = formKey.currentState;
si (formulaire.valider())
{ formulaire.save();
si (ceci.id == 0)
dépenses.add(Dépense(0, _montant, _date, _catégorie)); else
Navigateur.pop(contexte);
}
}
@outrepasser
Création de widget (contexte de construction)
{ return Scaffold(
clé : scaffoldKey,
appBar :
AppBar( titre : Texte('Entrez les détails des dépenses'),
170
Machine Translated by Google
Battement
),
corps :
Padding( padding : const EdgeInsets.all(16.0), enfant :
Form( clé : formKey,
enfant :
Column( enfants :
[ TextFormField( style :
TextStyle(fontSize : 22), décoration : const
InputDecoration( icône : const Icon(Icons.monetization_on),
labelText : 'Montant', labelStyle : TextStyle(fontSize :
18)),
validateur : (val) {
Motif motif = r'^[19]\d*(\.\d+)?$'; RegExp regex = new RegExp(pattern);
if (!regex.hasMatch(val)) return 'Entrez un nombre valide'; else
retourner null;
},
valeur initiale :
identifiant == 0 ? '' : dépenses.byId(id).amount.toString(), onSaved: (val) =>
_amount = double.parse(val), ), TextFormField( style: TextStyle(fontSize:
const
InputDecoration( icône: const Icon(Icons.category),
labelText:
: dépenses.byId(id).category.toString(),
171
Machine Translated by Google
Battement
),
RaisedButton( onPressed:
_submit, enfant: nouveau
texte('Soumettre'), ), ], ), ), ), );
}
}
• Ici,
• La propriété validateur de TextFormField est utilisée pour valider l'élément de formulaire avec
Modèles RegEx.
• La fonction _submit est utilisée avec l'objet dépenses pour ajouter ou mettre à jour les dépenses dans la base de
données.
importer 'Expense.dart';
vide main() {
dépenses finales = ExpenseListModel();
runApp(ScopedModel<ExpenseListModel>( modèle :
dépenses, enfant :
MyApp(), ));
build(BuildContext context) {
return MaterialApp( titre :
'Dépenses', thème :
ThemeData( primarySwatch :
172
Machine Translated by Google
Battement
@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar( title:
Texte(this.title), ), corps:
); } else
{ index = index 1; return
Dismissible( clé :
Key(expenses.items[index].id.toString()), onDismissed : (direction) {
dépenses.delete(dépenses.éléments[index]);
Scaffold.of(context).showSnackBar(SnackBar( content:
Text("Élément avec identifiant, " +
expenses.items[index].id.toString() + " est rejeté")));
},
enfant : ListTile( onTap :
()
{ Navigator.push( contexte,
},
en tête : icône(Icons.monetization_on), en queue :
icône(Icons.keyboard_arrow_right), en titre :
texte(expenses.items[index].category +
": " +
dépenses.éléments[index].montant.toString() + " \nsont dépensés
"
pour +
dépenses.éléments[index].formattedDate, style :
TextStyle(fontSize: 18, fontStyle: FontStyle.italic),)));
173
Machine Translated by Google
Battement
retourner Divider(); }, ); }, ),
Navigator.push( contexte,
« Incrément », enfant :
icône(Icons.add), ); }));
}
}
@outrepasser
_FormPageState createState() => _FormPageState(id: id, dépenses: dépenses); }
double _montant;
DateHeure _date;
Chaîne _category;
174
Machine Translated by Google
Battement
vide _submit() {
forme finale = formKey.currentState;
si (formulaire.valider())
{ formulaire.save();
si (ceci.id == 0)
dépenses.add(Dépense(0, _montant, _date, _catégorie)); else
Navigateur.pop(contexte);
}
}
@outrepasser
Création de widget (contexte de construction)
{ return Scaffold(
clé : scaffoldKey,
appBar :
AppBar( titre : Texte('Entrez les détails des
dépenses'), ),
corps : Padding( rembourrage : const
EdgeInsets.all(16.0),
enfant : Form( clé :
formKey,
enfant :
Column( enfants : [ TextFormField( style :
TextStyle(fontSize : 22), décoration : const
InputDecoration( icône : const
Icon(Icons.monetization_on), labelText : 'Montant', labelStyle : TextStyle(fontSize :
18)),
validateur : (val) {
Motif motif = r'^[19]\d*(\.\d+)?$'; RegExp regex = new RegExp(pattern);
if (!regex.hasMatch(val)) return 'Entrez un nombre valide'; else
retourner null;
},
valeur initiale :
identifiant == 0 ? ''
: dépenses.byId(id).amount.toString(), onSaved:
(val) => _amount = double.parse(val), ), TextFormField( style:
TextStyle(fontSize:
22), décoration: const InputDecoration(
175
Machine Translated by Google
Battement
const
InputDecoration( icône: const Icon(Icons.category),
labelText:
: dépenses.byId(id).category.toString(),
),
RaisedButton( onPressed:
_submit, enfant: nouveau
texte('Soumettre'), ), ], ), ), ), );
}
}
• Supprimez les dépenses existantes en faisant glisser l’entrée de dépense dans un sens ou dans l’autre.
176
Machine Translated by Google
Battement
177
Machine Translated by Google
Battement
178
Machine Translated by Google
Battement
179
Machine Translated by Google
Le framework Flutter fait un excellent travail en fournissant un excellent cadre pour créer des applications
mobiles de manière véritablement indépendante de la plateforme. En offrant une simplicité dans le processus
de développement, des performances élevées dans l'application mobile résultante, une interface utilisateur
riche et pertinente pour les platesformes Android et iOS, le framework Flutter permettra sûrement à de
nombreux nouveaux développeurs de développer des applications mobiles hautes performances et riches en
fonctionnalités dans un avenir proche.
180