Écrire votre première application Flutter, partie 2

Flutter est un kit d'interface utilisateur Google qui permet de développer des applications esthétiques compilées de manière native pour les mobiles, le Web et les ordinateurs de bureau, à partir d'un seul codebase. Gratuit et Open Source, Flutter fonctionne avec votre code existant. Il est utilisé par les développeurs et les entreprises du monde entier.

Dans cet atelier de programmation, vous allez améliorer une application mobile Flutter simple en y ajoutant de l'interactivité. Vous allez également créer une deuxième page (une route) que l'utilisateur pourra consulter. Vous allez enfin modifier le thème (la couleur) de l'application. Cet atelier de programmation s'appuie sur la partie 1, où vous créez une liste infinie à chargement différé. Nous vous fournissons toutefois le code de départ, si vous souhaitez commencer avec la partie 2.

Points abordés dans la partie 2

  • Écrire une application Flutter qui s'intègre naturellement dans iOS, Android et le Web
  • Utiliser l'actualisation à chaud pour accélérer le cycle de développement
  • Ajouter de l'interactivité à un widget avec état
  • Créer une deuxième page et y accéder
  • Modifier l'apparence d'une application à l'aide de thèmes

Objectifs de l'atelier (partie 2)

Dans cet atelier de programmation, vous commencerez avec une application mobile simple qui génère une liste infinie de noms d'entreprise. Quand vous aurez terminé, vos utilisateurs finaux pourront sélectionner et désélectionner des propositions afin d'enregistrer celles qu'ils préfèrent. Si vous appuyez sur l'icône de liste en haut à droite de la barre d'application, vous accédez à une nouvelle page (appelée route) qui ne répertorie que les éléments favoris.

Le fichier GIF animé suivant montre le fonctionnement de l'application finale.

7fcab088cd22cff7.gif

Qu'attendez-vous de cet atelier de programmation ?

Je suis novice en la matière et je voudrais avoir un bon aperçu. Je connais un peu le sujet, mais j'aimerais revoir certains points. Je recherche un exemple de code à utiliser dans mon projet. Je cherche des explications sur un point spécifique.

Si vous n'avez pas terminé la première partie, consultez la section Configurer votre environnement Flutter de l'atelier Écrire votre première application Flutter, partie 1 pour configurer l'environnement de développement Flutter.

Si vous avez déjà suivi la première partie de cet atelier de programmation, vous disposez déjà de l'application de démarrage startup_namer. Vous pouvez passer à l'étape suivante.

Si vous ne disposez pas de l'application startup_namer, vous pouvez l'obtenir en suivant les instructions ci-dessous.

b2f84ff91b0e1396.png Créez une application Flutter simple basée sur un modèle. Créez un projet Flutter appelé startup_namer, puis effectuez une migration vers Null Safety :

$ flutter create startup_namer
$ cd startup_namer
$ dart migrate --apply-changes

Vous allez principalement modifier lib/main.dart, où réside le code Dart.

b2f84ff91b0e1396.png Supprimez l'intégralité du code de lib/main.dart et remplacez-le par le code issu de ce fichier, qui permet d'afficher une liste infinie d'idées de noms d'entreprise.

b2f84ff91b0e1396.png Mettez à jour pubspec.yaml en ajoutant le package contenant des mots anglais :

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
  english_words: ^4.0.0-0    // NEW

Celui-ci génère des paires de mots aléatoires, qui sont autant d'idées de noms d'entreprise.

b2f84ff91b0e1396.png Lorsque vous affichez le fichier pubspec dans la vue de l'éditeur d'Android Studio, cliquez sur Pub get dans l'angle supérieur droit afin d'intégrer le package dans votre projet. Vous devriez obtenir le résultat suivant dans la console :

flutter pub get
Running "flutter pub get" in startup_namer...
Process finished with exit code 0

b2f84ff91b0e1396.png Exécutez l'application.

Faites défiler la page autant que vous le souhaitez pour consulter une liste d'idées de noms d'entreprise qui s'étend à l'infini.

Dans cette étape, vous allez ajouter une icône en forme de cœur à chaque ligne. À l'étape suivante, vous ferez en sorte que l'utilisateur puisse appuyer sur cette icône pour enregistrer des favoris.

b2f84ff91b0e1396.png Ajoutez un élément _saved Set à _RandomWordsState. L'élément Set stocke les paires de mots que l'utilisateur a ajoutées à ses favoris. Il est préférable d'utiliser Set au lieu de List, car une implémentation correcte de Set n'autorise pas les entrées en double.

class _RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[];
  final _saved = <WordPair>{};     // NEW
  final _biggerFont = TextStyle(fontSize: 18.0);
  ...
}

b2f84ff91b0e1396.png Dans la fonction _buildRow, ajoutez une vérification alreadySaved pour valider qu'une paire de mots n'a pas déjà été ajoutée aux favoris.

Widget _buildRow(WordPair pair) {
  final alreadySaved = _saved.contains(pair);  // NEW
  ...
}

Dans _buildRow(), vous ajouterez également des icônes en forme de cœur aux objets ListTile pour activer la fonction d'ajout aux favoris. À l'étape suivante, vous ajouterez la possibilité d'intéragir avec ces icônes.

b2f84ff91b0e1396.png Ajoutez les icônes après le texte, comme illustré ci-dessous :

Widget _buildRow(WordPair pair) {
  final alreadySaved = _saved.contains(pair);
  return ListTile(
    title: Text(
      pair.asPascalCase,
      style: _biggerFont,
    ),
    trailing: Icon(   // NEW from here...
      alreadySaved ? Icons.favorite : Icons.favorite_border,
      color: alreadySaved ? Colors.red : null,
    ),                // ... to here.
  );
}

b2f84ff91b0e1396.png Effectuez une actualisation à chaud de l'application.

Une icône en forme de cœur doit s'afficher sur chaque ligne. Celle-ci n'est pas encore interactive.

Android

iOS

Des problèmes ?

Si votre application ne fonctionne pas correctement, vous pouvez utiliser le code contenu dans le lien suivant pour résoudre la situation.

Dans cette étape, vous ferez en sorte que l'utilisateur puisse appuyer sur les icônes en forme de cœur. Lorsque l'utilisateur appuie sur une entrée de la liste pour modifier son état, la paire de mots est ajoutée ou supprimée des favoris enregistrés.

Pour ce faire, vous devez modifier la fonction _buildRow. Si une paire de mots a déjà été ajoutée aux favoris, appuyez dessus pour la supprimer. Lorsqu'une icône a été appuyée, la fonction appelle setState() pour avertir le framework que l'état a été modifié.

b2f84ff91b0e1396.png Ajoutez onTap à la méthode _buildRow, comme indiqué ci-dessous :

Widget _buildRow(WordPair pair) {
  final alreadySaved = _saved.contains(pair);
  return ListTile(
    title: Text(
      pair.asPascalCase,
      style: _biggerFont,
    ),
    trailing: Icon(
      alreadySaved ? Icons.favorite : Icons.favorite_border,
      color: alreadySaved ? Colors.red : null,
    ),
    onTap: () {      // NEW lines from here...
      setState(() {
        if (alreadySaved) {
          _saved.remove(pair);
        } else {
          _saved.add(pair);
        }
      });
    },               // ... to here.
  );
}

b2f84ff91b0e1396.png Effectuez une actualisation à chaud de l'application.

Vous pouvez appuyer sur une icône pour ajouter l'entrée aux favoris ou l'en supprimer. Lorsque vous appuyez sur une icône, une animation de tache de couleur partant du point d'appui est affichée.

Android

iOS

Des problèmes ?

Si votre application ne fonctionne pas correctement, vous pouvez utiliser le code contenu dans le lien suivant pour résoudre la situation.

Dans cette étape, vous allez ajouter une nouvelle page (appelée route dans Flutter) qui affiche les favoris. Vous apprendrez à naviguer entre la route d'accueil et la nouvelle route.

Dans Flutter, le fichier Navigator gère une pile contenant les routes de l'application. Le fait d'intégrer une route à la pile de Navigator met à jour l'affichage vers cette route. Le fait de retirer une route de la pile de Navigator renvoie l'affichage à la route précédente.

Vous allez ensuite ajouter une icône de liste à AppBar dans la méthode build pour _RandomWordsState. Lorsque l'utilisateur clique sur cette l'icône, une nouvelle route contenant les favoris enregistrés est intégrée à Navigator, qui affiche l'icône.

b2f84ff91b0e1396.png Ajoutez l'icône et l'action correspondante à la méthode build :

class _RandomWordsState extends State<RandomWords> {
  ...
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Startup Name Generator'),
        actions: [
          IconButton(icon: Icon(Icons.list), onPressed: _pushSaved),
        ],
      ),
      body: _buildSuggestions(),
    );
  }
  ...
}

b2f84ff91b0e1396.png Ajoutez une fonction _pushSaved() à la classe _RandomWordsState.

  void _pushSaved() {
  }

b2f84ff91b0e1396.png Effectuez une actualisation à chaud de l'application. L'icône de liste a114478ae13b853.png s'affiche dans la barre d'application. Si vous appuyez dessus, rien ne se produit, car la fonction _pushSaved est vide.

Vous allez ensuite créer une route et l'intégrer à la pile de Navigator. Cette action modifie l'écran pour qu'il affiche la nouvelle route. Le contenu de la nouvelle page est intégré dans la propriété builder de MaterialPageRoute dans une fonction anonyme.

b2f84ff91b0e1396.png Appelez Navigator.push, comme illustré ci-dessous, ce qui permet d'intégrer la route à la pile du navigateur. L'IDE renvoie une erreur de code non valide que vous pourrez résoudre dans la section suivante.

void _pushSaved() {
  Navigator.of(context).push(
  );
}

Vous allez maintenant ajouter MaterialPageRoute et son générateur. Pour l'instant, ajoutez le code qui génère les lignes ListTile. La méthode divideTiles() de ListTile ajoute un espacement horizontal entre chaque ListTile. La variable divided contient les dernières lignes converties en liste par la fonction de commodité, toList().

b2f84ff91b0e1396.png Ajoutez le code, comme indiqué dans l'extrait de code suivant :

  void _pushSaved() {
    Navigator.of(context).push(
      MaterialPageRoute<void>(
        // NEW lines from here...
        builder: (BuildContext context) {
          final tiles = _saved.map(
            (WordPair pair) {
              return ListTile(
                title: Text(
                  pair.asPascalCase,
                  style: _biggerFont,
                ),
              );
            },
          );
          final divided = ListTile.divideTiles(
            context: context,
            tiles: tiles,
          ).toList();

          return Scaffold(
            appBar: AppBar(
              title: Text('Saved Suggestions'),
            ),
            body: ListView(children: divided),
          );
        }, // ...to here.
      ),
    );
  }

La propriété builder renvoie un élément Scaffold contenant la barre d'application de la nouvelle route nommée SavedSuggestions. Le corps de la nouvelle route est constitué d'un fichier ListView contenant les lignes ListTiles. Chaque ligne est séparée par un séparateur.

b2f84ff91b0e1396.png Effectuez une actualisation à chaud de l'application. Ajoutez certaines propositions aux favoris, puis appuyez sur l'icône de la liste dans la barre d'application. La nouvelle route s'affiche, contenant les favoris. Notez que le navigateur ajoute un bouton "Retour" à la barre d'application. Vous n'avez pas à implémenter explicitement Navigator.pop. Appuyez sur le bouton "Retour" pour revenir à la route d'accueil.

iOS : route principale

iOS : route de propositions enregistrées

Des problèmes ?

Si votre application ne fonctionne pas correctement, vous pouvez utiliser le code contenu dans le lien suivant pour résoudre la situation.

Dans cette étape, vous allez modifier le thème de l'application. Le thème contrôle l'apparence de votre application. Vous pouvez utiliser le thème par défaut, qui dépend de l'appareil physique ou de l'émulateur, ou le personnaliser pour l'adapter à votre branding.

Vous pouvez facilement modifier le thème d'une application en configurant la classe ThemeData. L'application utilise le thème par défaut. Vous modifierez la couleur principale en blanc.

b2f84ff91b0e1396.png Modifiez la couleur de la classe MyApp :

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Startup Name Generator',
      theme: ThemeData(          // Add the 3 lines from here...
        primaryColor: Colors.white,
      ),                         // ... to here.
      home: RandomWords(),
    );
  }
}

b2f84ff91b0e1396.png Effectuez une actualisation à chaud de l'application. L'arrière-plan est entièrement blanc, de même que la barre d'application.

À titre d'exercice, utilisez ThemeData pour modifier d'autres aspects de l'interface utilisateur. La classe Colors de la bibliothèque Material fournit de nombreuses constantes de couleur que vous pouvez appliquer. L'actualisation à chaud permet de tester rapidement et facilement les modifications de l'interface utilisateur.

Android

iOS

Des problèmes ?

Si vous rencontrez des difficultés, utilisez le code contenu dans le lien suivant pour consulter le code de l'application finale.

Vous avez écrit une application Flutter interactive qui s'exécute sous iOS et Android en effectuant les étapes suivantes :

  • Rédiger du code Dart
  • Utiliser l'actualisation à chaud pour accélérer le cycle de développement
  • Implémenter un widget avec état pour améliorer l'interactivité de votre application
  • Créer une route et ajouter une logique pour passer entre la route d'accueil et la nouvelle route
  • Modifier l'apparence de votre application à l'aide de thèmes

Pour en savoir plus sur le SDK Flutter, consultez les ressources suivantes :

Autres ressources :

Vous pouvez également échanger avec la communauté Flutter.