Créer une première application toute simple avec Flutter


Avatar de Pierre Courtois

Vous avez installé Flutter et appris les bases de la syntaxe du langage Dart. Vient maintenant le moment tant attendu de commencer à coder avec Flutter. Pourquoi ne pas apprendre les bases en se servant du code de base qui est fourni par défaut lorsque vous créez un dossier.


garçon qui travaille sur son application le soir

1. Créer un projet

La première étape pour commencer à coder votre application est de créer un dossier Flutter, qui va contenir tous les éléments dont vous aurez besoin. Dans le terminal, utilisez la commande cd, puis le nom du dossier dans lequel vous allez garder vos applications. Par exemple, si vous souhaitez stocker vos projets dans un dossier « Apps », entrez cd Apps.

Idéalement, créez un dossier “development”, dans lequel vous aller garder tous vos projets ainsi que vos ressources Flutter. C’est une pratique répandue parmi les développeurs.  Cela vous permettra de retrouver facilement vos applications et de garder un environnement de travail propre et cohérent.

Une fois au bon endroit, utilisez la commande flutter create, suivi du nom que vous voulez donner à votre dossier. Par exemple si votre application s’appelle premiere_app, entrez la commande flutter create premiere_app. Un projet va alors être ajouté dans le dossier dans lequel vous vous trouvez. Vous allez ensuite pouvoir l’ouvrir dans Visual studio.

Comprendre à quoi servent les fichiers dans votre projet

Lorsque vous ouvrez votre application dans Visual studio, vous allez voir toutes les ressources que votre application utilise, dans une colonne à gauche. Il n’est pas nécessaire de comprendre à quoi tous ces fichiers servent pour coder votre application, mais cela ne fait pas de mal d’en parler un peu. Voici les dossiers et fichiers les plus importants : 

  • android, qui comme son nom l’indique contient toutes les ressources permettant à votre application Flutter d’être lancée sur des plateformes utilisant Android. Sachez qu’il est aussi possible et même parfois nécessaire, d’ouvrir ce dossier dans Android studio
  • ios, qui comme son nom l’indique contient toutes les ressources permettant à votre application Flutter d’être lancée sur des plateformes utilisant IOS. Sachez qu’il est aussi possible et même parfois nécessaire, d’ouvrir ce dossier dans Xcode ;
  • lib, qui va contenir tous vos fichiers en .dart, qui sont les fichiers sur lesquels vous allez coder votre application Flutter. On y trouve notamment le fichier main.dart que vous ne devez surtout pas supprimer car il sert de point de départ à votre application ; 
  • pubspec.yaml, qui est le fichier sur lequel vous allez importer vos packages. C’est aussi là que vous allez pouvoir changer le numéro de version de votre application quand vous allez publier des mises à jour.

2. Apprendre les bases de Flutter avec une première application

Si vous ouvrez pour la première fois le fichier main.dart, contenu dans le dossier lib de votre application, vous allez constater que des lignes de code ont déjà été écrites. Ceci est une première application d’exemple qui est fournie avec Flutter et qui vous permet de vous familiariser avec le Dart :

import 'package:flutter/material.dart';


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


class MyApp extends StatelessWidget {
 const MyApp({super.key});


 @override
 Widget build(BuildContext context) {
   return MaterialApp(
     title: 'Flutter Demo',
     theme: ThemeData(
       colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
       useMaterial3: true,
     ),
     home: const MyHomePage(title: 'Flutter Demo Home Page'),
   );
 }
}


class MyHomePage extends StatefulWidget {
 const MyHomePage({super.key, required this.title});
 final String title;


 @override
 State<MyHomePage> createState() => _MyHomePageState();
}


class _MyHomePageState extends State<MyHomePage> {
 int _counter = 0;


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


 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       backgroundColor: Theme.of(context).colorScheme.inversePrimary,
       title: Text(widget.title),
     ),
     body: Center(
       child: Column(
         mainAxisAlignment: MainAxisAlignment.center,
         children: <Widget>[
           const Text(
             'You have pushed the button this many times:',
           ),
           Text(
             '$_counter',
             style: Theme.of(context).textTheme.headlineMedium,
           ),
         ],
       ),
     ),
     floatingActionButton: FloatingActionButton(
       onPressed: _incrementCounter,
       tooltip: 'Increment',
       child: const Icon(Icons.add),
     ), 
   );
 }
}

Si vous débutez, tout cela doit ressembler à du charabia. Mais en réalité, ce code est relativement simple à comprendre une fois vu point par point et va vous permettre de mettre un premier pied à l’étrier. Faisons donc un petit tour des différentes parties de celui-ci, pour comprendre à quoi elles servent .

Lancer votre application avec fonction main()

Tout en haut de votre dossier main.dart, vous allez trouver la fonction main(), qui doit toujours être le point de départ de n’importe quel application Flutter. En effet, c’est grâce à elle que mon code va pouvoir se lancer.

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

Je ne m’attarde pas trop ici sur la signification du void, devant main. Notez simplement que les parenthèses () suivi d’accolades {} sont une syntaxe de Flutter, propre aux fonctions. Les parenthèses servent à récupérer des paramètres, alors que les actions de ma fonction vont se placer entre les accolades.

Ici, je demande à ma fonction main() de lancer mon application, avec la méthode runApp(). Celle-ci va quant à elle prendre comme argument le premier widget que je souhaite montrer au lancement de mon application (généralement une page). En l’occurence, celui-ci s’appelle ici MyApp().

Créer une page de votre application à partir d’un « Widget »

class MyApp extends StatelessWidget {
 const MyApp({super.key});


 @override
 Widget build(BuildContext context) {
   return MaterialApp(
     title: 'Flutter Demo',
     theme: ThemeData(
       colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
       useMaterial3: true,
     ),
     home: const MyHomePage(title: 'Flutter Demo Home Page'),
   );
 }
}

Comme expliqué précédemment « la page » qui est montrée en premier lorsque l’application se lance est contenu dans un widget appelé MyApp. Pour comprendre comment celle-ci est construire, il est important de saisir à quoi servent

  • Les Stateless Widget ; 
  • La Material App() ;

Comprendre la notion de Widget pour coder le contenu de votre application

Une notion centrale de Flutter est celle des Widgets. Pour les décrire de manière simple, ceux-ci sont des objets que vous allez pouvoir créer et manipuler à votre guise pour construire votre application. Un widget peut par exemple être : 

  • Un message d’erreur ;
  • Un bouton ; 
  • Un menu ; 
  • Une liste ;
  • Ou même une page entière de votre application (Composée de plusieurs widgets) ;  

Un widget peut être composé d’un seul élément (par exemple un texte) ou bien de plusieurs éléments qui composent quelque chose de plus grand (Une page). Ici, ma page MyApp(), n’est qu’un très gros widget qui se compose de plusieurs widgets, eux mêmes potentiellement composées d’autres widgets. Je pourrais par exemple, créer :

  • Un widget Image(), qui contiendrait simplement une image ; 
  • Et un widget Boutons(), qui contiendrait lui même une ligne composée de plusieurs boutons pour aimer, commenter, partager, etc. 

Construire vos pages avec des Stateful et Stateless widgets

Maintenant que la notion de widgets est clarifiée, il est important de noter qu’il y en a deux qui vont nous intéresser pour construire nos pages ou des éléments de celles-ci. Si vous retournez sur le code fourni par Flutter, vous verrez que MyApp() est ce qu’on appelle un Stateless widget. Mais que veut dire Stateless et pourquoi utiliser ce type de widget pour construire ma page et pas un autre ? Pour le comprendre, il faut avoir une idée ce qui se passe quand on réalise une action sur notre application.

Admettons que j’ai un widget ListDeCourse(), qui contient une liste d’articles que je veux supprimer une fois que je les ai achetés. Lorsque je vais appuyer sur le bouton supprimer, je souhaite à priori voir ma liste s’actualiser et l’article disparaitre. Or, la particularité de Flutter est que le widget à modifier ne va pas s’actualiser. Ma page va en fait se reconstruire de 0 pour me montrer une nouvelle liste qui ne contient plus mon item. C’est alors qu’interviennent ce qu’on appelle les Stateless et les Stateful widgets.

Dans le cas présent, mon widget MyApp() ne change pas d’état pendant l’utilisation de mon application. Je peux donc lui donner une nature de type Stateless.

Voilà un dernier exemple pour bien comprendre ce concept. Admettons que mon écran affiche un carré qui doit changer de couleur à chaque fois que je clique sur un bouton. Mon carré devra être contenu dans un Stateful widget. En effet, il va se reconstruire avec une nouvelle couleur à chaque fois que ma fonction va se lancer. Mon bouton, en revanche, peut être construit séparement avec un Stateless widget, puisqu’il va à priori rester le même. 

Si votre widget contient plusieurs éléments, dont certains sont dynamiques et d’autres pas, alors c’est le comportement dynamique qui l’emporte. Vous devrez donc utiliser un Stateful widget. 

Material App()

La MaterialApp est un type de widget qui va vous permettre de construire les pages de votre application et qui va être pris comme paramètre de la fonction runApp(). Dans l’exemple qui nous est donné par Flutter, la MaterialApp se compose d’un titre, d’un thème et d’une variable home. C’est dans cette dernière que l’on va venir placer notre Scaffold(), qui est un widget que je décris plus en détail par la suite.

Ce widget va donc en quelque sorte vous servir de page blanche, sur laquelle vous allez pouvoir placer les différents éléments qui vont apparaitre à l’écran. 

Ajouter du contenu à votre page

Notre « page blanche » MyApp() est créée, reste à lui ajouter du contenu dans un nouveau widget MyHomePage(), qui sera placé comme argument de son paramètre home. Pour schématiser, MyApp() sert ici de cadre et MyHomePage est la peinture contenue dans celui-ci.

MyHomePage est un widget de type Stateful, ce qui veut dire qu’il peut se reconstruire durant l’utilisation de l’app. Ce comportement va nous être utile, puisque la variable counter qui affichée à l’écran doit augmenter de 1, à chaque fois que vous appuyez sur le bouton +.

class MyHomePage extends StatefulWidget {
 const MyHomePage({super.key, required this.title});
 final String title;


 @override
 State<MyHomePage> createState() => _MyHomePageState();
}


class _MyHomePageState extends State<MyHomePage> {
 int _counter = 0;


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


 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       backgroundColor: Theme.of(context).colorScheme.inversePrimary,
       title: Text(widget.title),
     ),
     body: Center(
       child: Column(
         mainAxisAlignment: MainAxisAlignment.center,
         children: <Widget>[
           const Text(
             'You have pushed the button this many times:',
           ),
           Text(
             '$_counter',
             style: Theme.of(context).textTheme.headlineMedium,
           ),
         ],
       ),
     ),
     floatingActionButton: FloatingActionButton(
       onPressed: _incrementCounter,
       tooltip: 'Increment',
       child: const Icon(Icons.add),
     ), 
   );
 }
}

Comment déclarer un stateful widget ?

La première chose à faire pour utiliser un widget de type Stateless ou Stateful est de : 

  1. Le créer ; 
  2. D’annoncer les variables dont il peut avoir besoin pour se construire ; 
  3. D’annoncer les variables et fonctions qui seront utilisées dedans. 
1. Créer un widget

Dans l’application d’exemple fournie par Flutter, voici comment se présente le stateful widget MyHomePage : 

class MyHomePage extends StatefulWidget {
 const MyHomePage({super.key, required this.title});
 final String title;


 @override
 State<MyHomePage> createState() => _MyHomePageState();
}


class _MyHomePageState extends State<MyHomePage> {
 int _counter = 0;


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


 @override
 Widget build(BuildContext context) {
   return Containt()
}
Astuce pour créer vos widgets

Vous n’avez pas besoin de connaître par coeur la syntaxe des stateless et des stateful widgets. Vous pouvez simplement commencer à taper « st » sur une ligne vide, en dehors de toute classe. Les options Flutter Stateless widget et Flutter Stateful widget devraient alors apparaître.

2. Définir des variables obligatoires pour utiliser un widget

Si on prend MyHomePage(), on observe dans sa déclaration la ligne final String title; ainsi que juste au dessus required this.title. Ceci indique que ce widget nécessite de définir une variable de type String “title” pour pouvoir être utilisé. Et en effet, si on regarde le paramètre home dans MyApp(), on peut voir qu’une valeur de « Flutter Demo Home Page » a été donnée à la variable title :

home: const MyHomePage(title: 'Flutter Demo Home Page'),

Ce comportement va nous permettre de personnaliser notre widget et de le modifier à l’infini, selon les valeurs rentrées. Par exemple, je pourrais exiger d’avoir le pseudo et la photo de l’utilisateur pour construire ma page de profil. Ceci me permettrait de personnaliser mon contenu selon les valeurs renvoyées.

3. Annoncer des variables et des fonctions utilisables dans mon widget

Enfin, vous allez aussi pouvoir définir des variables et des fonctions qui ne seront utilisables qu’au sein du widget dans lesquelles elles sont définies. Si on reprend MyHomePage, on voit qu’une variable _counter, de type int et égale à 0, ainsi qu’une fonction _incrementCounter() ont été déclarées. C’est grâce à elles que je vais pouvoir afficher un chiffre à l’écran et le modifier à chaque fois que je vais cliquer sur le bouton +.

Les variables créées dans un widget ne peuvent être utilisées qu’au sein de celui-ci. Si vous souhaitez pouvoir y accéder à plusieurs endroits de votre widget tree, il vaudra mieux les déclarer en haut de votre fichier dart, en dehors de toute classe.

Créer la charpente d’une page grâce au Scaffold

Le Scaffold, ou “échaffaudage” sert en quelque sorte de squelette, ou de « charpente » à votre page. Il va se composer de plusieurs éléments, qui posent les fondations d’une page d’application, notamment : 

  • Une appBar (barre horizontale en haut de l’application) 
  • Un body (le centre de votre page, où va se trouver le contenu principal) ; 
  • Une bottomNavigationBar (barre horizontale en bas de l’application).

Le Scaffold peut prendre bien d’autres paramètres, mais voici les principaux. Enfin, sachez qu’une page peut très bien ne pas avoir d’appBar ou de bottomNavigationBar, mais doit au moins avoir un body. 

Présentation rapide de certains widgets et méthodes utilisés dans cet exemple

Pour conclure ce guide, je vais vous présenter certains des éléments utilisés dans cette application. Vous pourrez ainsi commencer à vous familiariser avec le Dart : 

appBar: AppBar(
       backgroundColor: Theme.of(context).colorScheme.inversePrimary,
       title: Text(widget.title),
     ),

backgroundColor : Permet de définir la couleur de l’appBar. Ici, le cas est un peu particulier, puisque le widget récupère la couleur deepPurple définie plus haut. Mais la manière la plus simple de définir une couleur est d’utiliser Colors.laCouleurDeVotreChoix. Vous pouvez retrouver ici la liste des couleurs primaires fournies par Flutter.

title : Permet de définir le titre de votre appBar sous la forme d’un Text(). Ici le titre est widget.title, qui est la variable requise pour construire le widget. Le titre renvoyé sera donc ‘Flutter Demo Home Page’.

body: Center(
       child: Column(
         mainAxisAlignment: MainAxisAlignment.center,
         children: <Widget>[
           const Text(
             'You have pushed the button this many times:',
           ),
           Text(
             '$_counter',
             style: Theme.of(context).textTheme.headlineMedium,
           ),
         ],
       ),
     ),

Center : Permet de centrer un élément au milieu de son parent. Ici, le parent est body, donc l’élément sera centré au milieu de l’écran.

child : child (enfant) est un paramètre qui permet de placer un widget dans un autre widget. Ici, le widget Column() est l’enfant du widget Center().

Column() : Permet d’empiler les widgets qui se trouvent dedans, sous la forme d’une colonne. À noter qu’une colonne peut tout à fait contenir d’autres colonnes ou des lignes (Row()).

mainAxisAlignment : Ce paramètre permet de positionner les widgets qui se trouvent dans la colonne, par rapport à l’axe horizontal. Ici, mainAxisAlignment a une valeur de center, donc les éléments seront placés au centre de la colonne.

children : Suivi par des crochets [ ], children, contient tous les widgets mis dans le widget column. Ce paramètre est également utilisé par le widget Row() (ligne). Pour en apprendre plus sur comment organiser vos éléments en lignes et en colonnes, je vous invite à lire le guide que j’ai rédigé sur le widget Column() et celui-ci sur Row().

Text() : Le widget Text(), comme son nom l’indique, permet d’afficher du texte à l’écran. Ici, deux exemples sont donnés : 

  • Un avec du texte entre guillemet ; 
  • Un avec la variable _counter, mise aussi entre guillemet. Un signe dollar est mis devant, pour signifier que c’est une variable et non pas du texte. Parfois, il est aussi nécessaire de mettre la variable dans des accolades, par exemple ${_counter.toString()}.

Un style peut être donné à votre texte, via le paramètre style. L’exemple fourni par Flutter n’est pas le plus simple, donc sachez que vous pouvez simplement utiliser utiliser style : Textstyle().

3. Tester votre application Flutter

Pour tester votre application, cliquez sur le bouton en bas à droite de la fenêtre Visual Studio, avec marqué Chrome (web-javascript). Une fenêtre va s’ouvrir en haut avec tous les simulateurs que vous avez à votre disposition. Vous pouvez ainsi faire vos tests sur : 

  1. Une page Chrome ; 
  2. Une page safari ; 
  3. Tous les émulateurs Android que vous aurez créés via Android Studio ; 
  4. Tous les émulateurs IOS qui utilisent la version minimal du système d’exploitation que vous aurez indiqué sur Xcode (Par exemple, tous les devices qui fonctionnent sur IOS 17.0).

Une fois que vous aurez ouvert un émulateur, rendez-vous sur votre fichier main.dart. De là, cliquez sur le bouton play en haut à droite de la fenêtre. Pour l’instant, vous pouvez cliquer sur “Run without debugging”.

Une autre manière de lancer l’application est d’entrer flutter run dans le terminal de commande de Visual Studio. 

Vous devriez voir un texte en jeune ou en bleu, apparaitre dans votre console de débogage, qui signifie que l’application est bien en train de se lancer. Le premier lancement peut prendre un peu de temps (jusqu’à 2 ou 3 minutes), soyez donc patient. 

4. Commencez à coder votre propre application

Vous n’en êtes qu’au début de l’apprentissage de Flutter, mais avez déjà de quoi commencer à coder une application très basique. Je vous conseille d’exploiter le code de base fournie par Flutter pour apprendre à faire apparaître des éléments et les placer sur l’écran. N’ayez pas peur de le casser, vous pourrez toujours récupérer le code de base ici.

La meilleure manière d’apprendre à coder est de tester des fonctions toutes simples, puis d’essayer de les combiner pour arriver petit à petit à quelque chose de plus complexe. Par exemple, essayez de modifier le code pour donner une couleur différente à _counter, à chaque fois que vous appuyez sur le bouton +. Je vous donne un indice, il existe un Widget Color.fromARGB qui prend comme paramètre 4 nombre compris entre 0 et 255. Peut-être que ces nombres pourraient être contenus dans des variables. 

Enfin, lorsque vous passez votre souris sur un widget, un panneau d’aide s’affiche avec les différents paramètres que celui peut contenir. Utilisez cette documentation pour découvrir tout ce que recèlent les widgets que vous utilisez et les exploiter le plus possible. 

Conclusion

Le code de base fourni par Flutter est un excellent point de départ pour comprendre les concepts nécessaires au développement de votre application. Utilisez-le pour tester et observer comment vos modifications affectent l’apparence de votre projet. La prochaine étape sera d’explorer quelques widgets essentiels qui sont à la base de toute application. Cela vous permettra de commencer rapidement à concrétiser votre idée.

Découvrir les widgets de base

Avatar de Pierre Courtois