Animer des applications avec Flutter

Shubham

A propos de l’auteur

Un développeur de logiciels full stack le jour et un développeur d’applications mobiles la nuit. Quand je ne travaille pas, j’aime cuisiner et jouer à des jeux sur PC.En savoir plus surShubham↬

  • 14 min de lecture
  • Applications,Animation
  • Enregistré pour une lecture hors ligne
  • Partager sur Twitter, LinkedIn
Flutter offre un excellent support d’animation pour les applications multiplateformes. Cet article explore la nouvelle façon non conventionnelle et une façon plus facile d’ajouter des animations aux apps. Qu’est-ce que ces nouveaux widgets « Animation and Motion » et comment pouvons-nous les utiliser pour ajouter des animations simples et complexes ?

Les apps pour n’importe quelle plateforme sont louées lorsqu’elles sont intuitives, belles et fournissent un retour agréable aux interactions de l’utilisateur. L’animation est l’un des moyens d’y parvenir.

Flutter, un framework multiplateforme, a mûri au cours des deux dernières années pour inclure un support web et de bureau. Il a acquis la réputation que les applications développées avec lui sont fluides et belles. Avec sa riche prise en charge des animations, sa façon déclarative d’écrire l’interface utilisateur, le « Hot Reload » et d’autres fonctionnalités, il est maintenant un framework multiplateforme complet.

Si vous débutez avec Flutter et que vous voulez apprendre une façon non conventionnelle d’ajouter des animations, alors vous êtes au bon endroit : nous allons explorer le royaume des widgets d’animation et de mouvement, une façon implicite d’ajouter des animations.

Flutter est basé sur le concept des widgets. Chaque composant visuel d’une application est un widget – pensez à eux comme à des vues dans Android. Flutter fournit un support d’animation en utilisant une classe Animation, un objet « AnimationController » pour la gestion, et « Tween » pour interpoler la plage de données. Ces trois composants fonctionnent ensemble pour fournir une animation fluide. Comme cela nécessite une création et une gestion manuelles de l’animation, c’est connu comme une façon explicite d’animer.

Maintenant, laissez-moi vous présenter les widgets d’animation et de mouvement. Flutter fournit de nombreux widgets qui supportent intrinsèquement l’animation. Il n’est pas nécessaire de créer un objet d’animation ou un quelconque contrôleur, car toute l’animation est gérée par cette catégorie de widgets. Il suffit de choisir le widget approprié pour l’animation requise et de transmettre les valeurs des propriétés du widget à animer. Cette technique est une manière implicite d’animer.

Hiérarchie d’animation dans Flutter. (Grand aperçu)

Le tableau ci-dessus établit grossièrement la hiérarchie des animations dans Flutter, comment les animations explicites et implicites sont prises en charge.

Certains des widgets animés couverts dans cet article sont :

  • AnimatedOpacity
  • AnimatedCrossFade
  • AnimatedAlign
  • AnimatedPadding
  • AnimatedSize
  • AnimatedPositioned.

Flutter fournit non seulement des widgets animés prédéfinis mais aussi un widget générique appelé AnimatedWidget, qui peut être utilisé pour créer des widgets personnalisés implicitement animés. Comme il ressort de leur nom, ces widgets appartiennent à la catégorie des widgets animés et de mouvement, et ils ont donc des propriétés communes qui nous permettent de rendre les animations beaucoup plus fluides et plus belles.

Laissons-moi expliquer ces propriétés communes maintenant, car elles seront utilisées plus tard dans tous les exemples.

  • duration
    La durée sur laquelle animer les paramètres.
  • reverseDuration
    La durée de l’animation inverse.
  • curve
    La courbe à appliquer lors de l’animation des paramètres. Les valeurs interpolées peuvent être tirées d’une distribution linéaire ou, si et quand cela est spécifié, peuvent être tirées d’une courbe.

Débutons le voyage en créant une application simple que nous appellerons « Quoted ». Elle affichera une citation aléatoire à chaque fois que l’app démarrera. Deux choses à noter : premièrement, toutes ces citations seront codées en dur dans l’application ; et deuxièmement, aucune donnée utilisateur ne sera sauvegardée.

Note : Tous les fichiers de ces exemples peuvent être trouvés sur GitHub.

Démarrer

Flutter devrait être installé et vous devrez vous familiariser avec le flux de base avant de continuer. Un bon endroit pour commencer est, « Using Google’s Flutter For Truly Cross-Platform Mobile Development ».

Créer un nouveau projet Flutter dans Android Studio.

Nouveau menu de projet Flutter dans Android Studio. (Grand aperçu)

Cela ouvrira un nouvel assistant de projet, où vous pourrez configurer les bases du projet.

Écran de sélection du type de projet Flutter. (Grand aperçu)

Dans l’écran de sélection du type de projet, il existe différents types de projets Flutter, chacun répondant à un scénario spécifique…. Pour ce tutoriel, choisissez Flutter Application et appuyez sur Suivant.

Vous devez maintenant entrer certaines informations spécifiques au projet : le nom et le chemin du projet, le domaine de l’entreprise, et ainsi de suite. Jetez un œil à l’image ci-dessous.

Écran de configuration de l’application Flutter. (Grand aperçu)

Ajouter le nom du projet, le chemin du SDK Flutter, l’emplacement du projet et une description facultative du projet. Appuyez sur Suivant.

Écran du nom du package de l’application Flutter. (Grand aperçu)

Chaque application (qu’elle soit Android ou iOS) nécessite un nom de paquet unique. Typiquement, vous utilisez l’inverse du domaine de votre site web ; par exemple, com.google ou com.yahoo. Appuyez sur Terminer pour générer une application Flutter fonctionnelle.

L’exemple de projet généré. (Grand aperçu)

Une fois le projet généré, vous devriez voir l’écran présenté ci-dessus. Ouvrez le fichier main.dart (mis en évidence dans la capture d’écran). Il s’agit du fichier principal de l’application. Le projet d’exemple est complet en lui-même, et peut être exécuté directement sur un émulateur ou un appareil physique sans aucune modification.

Remplacez le contenu du fichier main.dart par le bout de code suivant :

import 'package:animated_widgets/FirstPage.dart';import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Animated Widgets', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.blue, accentColor: Colors.redAccent, ), home: FirstPage(), ); }}

Ce code nettoie le fichier main.dart en ajoutant simplement des informations simples pertinentes pour créer une nouvelle application. La classe MyApp renvoie un objet : un widget MaterialApp, qui fournit la structure de base pour créer des apps conformes au Material Design. Pour rendre le code plus structuré, créez deux nouveaux fichiers dart dans le dossier lib : FirstPage.dart et Quotes.dart.

Le fichier FirstPage.dart. (Grand aperçu)

FirstPage.dart contiendra tout le code responsable de tous les éléments visuels (widgets) nécessaires à notre application Citations. Toute l’animation est gérée dans ce fichier.

Note : Plus loin dans l’article, tous les extraits de code pour chaque widget animé sont ajoutés à ce fichier comme enfants du widget Scaffold. Pour plus d’informations, Cet exemple sur GitHub pourrait être utile.

Débutez en ajoutant le code suivant à FirstPage.dart. C’est le code partiel où d’autres choses seront ajoutées plus tard.

import 'dart:math';import 'package:animated_widgets/Quotes.dart';import 'package:flutter/material.dart';class FirstPage extends StatefulWidget { @override State createState() { return FirstPageState(); }}class FirstPageState extends State with TickerProviderStateMixin { bool showNextButton = false; bool showNameLabel = false; bool alignTop = false; bool increaseLeftPadding = false; bool showGreetings = false; bool showQuoteCard = false; String name = ''; double screenWidth; double screenHeight; String quote; @override void initState() { super.initState(); Random random = new Random(); int quoteIndex = random.nextInt(Quotes.quotesArray.length); quote = Quotes.quotesArray; } @override Widget build(BuildContext context) { screenWidth = MediaQuery.of(context).size.width; screenHeight = MediaQuery.of(context).size.height; return Scaffold( appBar: _getAppBar(), body: Stack( children: , ), ); }}

Le fichier Quotes.dart. (Grand aperçu)

Le fichier Quotes.dart contient une liste de toutes les citations codées en dur. Un point à noter ici est que la liste est un objet statique. Cela signifie qu’elle peut être utilisée à d’autres endroits sans créer un nouvel objet de la classe Quotes. Ceci est choisi par conception, car la liste ci-dessus agit simplement comme un utilitaire.

Ajoutez le code suivant à ce fichier:

class Quotes { static const quotesArray = ;}

Le squelette du projet est maintenant prêt, alors étoffons Citation un peu plus.

AnimatedOpacity

Pour donner une touche personnelle à l’application, il serait bien de connaître le nom de l’utilisateur, alors demandons-le et montrons un bouton suivant. Jusqu’à ce que l’utilisateur entre son nom, ce bouton est caché, et il s’affichera gracieusement lorsqu’un nom sera donné. Nous avons besoin d’une sorte d’animation de visibilité pour le bouton, mais existe-t-il un widget pour cela ? Oui, il y en a un.

Enter AnimatedOpacity. Ce widget s’appuie sur le widget Opacity en ajoutant un support d’animation implicite. Comment l’utiliser ? Rappelez-vous notre scénario : nous avons besoin d’afficher un bouton suivant avec une visibilité animée. Nous enveloppons le widget bouton à l’intérieur du widget AnimatedOpacity, alimentons quelques valeurs appropriées et ajoutons une condition pour déclencher l’animation – et Flutter peut gérer le reste.

_getAnimatedOpacityButton() { return AnimatedOpacity( duration: Duration(seconds: 1), reverseDuration: Duration(seconds: 1), curve: Curves.easeInOut, opacity: showNextButton ? 1 : 0, child: _getButton(), );}
Animation de l’opacité du bouton suivant. (Grand aperçu)

Le widget AnimatedOpacity a deux propriétés obligatoires:

  • opacity
    Une valeur de 1 signifie complètement visible ; 0 (zéro) signifie caché. Pendant l’animation, Flutter interpole les valeurs entre ces deux extrêmes. Vous pouvez voir comment une condition est placée pour changer la visibilité, déclenchant ainsi l’animation.
  • child
    Le widget enfant qui aura sa visibilité animée.

Vous devriez maintenant comprendre comment il est vraiment simple d’ajouter une animation de visibilité avec le widget implicite. Et tous ces widgets suivent les mêmes directives et sont faciles à utiliser. Passons au suivant.

AnimatedCrossFade

Nous avons le nom de l’utilisateur, mais le widget attend toujours une entrée. Dans l’étape précédente, lorsque l’utilisateur saisit son nom, nous affichons le bouton suivant. Maintenant, lorsque l’utilisateur appuie sur le bouton, je veux arrêter d’accepter la saisie et afficher le nom saisi. Il y a de nombreuses façons de le faire, bien sûr, mais nous pouvons peut-être cacher le widget de saisie et afficher un widget de texte non modifiable. Essayons-le en utilisant le widget AnimatedCrossFade.

Ce widget nécessite deux enfants, car le widget passe de l’un à l’autre en fonction d’une certaine condition. Une chose importante à garder à l’esprit lors de l’utilisation de ce widget est que les deux enfants doivent avoir la même largeur. Si la hauteur est différente, le widget le plus grand sera coupé en bas. Dans ce scénario, deux widgets seront utilisés comme enfants : input et label.

_getAnimatedCrossfade() { return AnimatedCrossFade( duration: Duration(seconds: 1), alignment: Alignment.center, reverseDuration: Duration(seconds: 1), firstChild: _getNameInputWidget(), firstCurve: Curves.easeInOut, secondChild: _getNameLabelWidget(), secondCurve: Curves.easeInOut, crossFadeState: showNameLabel ? CrossFadeState.showSecond : CrossFadeState.showFirst, );}
Cross-fading entre le widget input et le widget name. (Grand aperçu)

Ce widget nécessite un ensemble différent de paramètres obligatoires:

  • crossFadeState
    Cet état travaille sur quel enfant montrer.
  • firstChild
    Spécifie le premier enfant pour ce widget.
  • secondChild
    Spécifie le deuxième enfant.

AnimatedAlign

À ce stade, l’étiquette du nom est positionnée au centre de l’écran. Elle aura bien meilleure allure en haut, car nous avons besoin du centre de l’écran pour afficher les guillemets. En d’autres termes, l’alignement du widget de l’étiquette du nom doit passer du centre au sommet. Et ne serait-il pas agréable d’animer ce changement d’alignement en même temps que l’animation de fondu enchaîné précédente ? Faisons-le.

Comme toujours, plusieurs techniques peuvent être utilisées pour y parvenir. Puisque le widget d’étiquette de nom est déjà aligné au centre, l’animation de son alignement serait beaucoup plus simple que de manipuler les valeurs haut et gauche du widget. Le widget AnimatedAlign est parfait pour ce travail.

Pour lancer cette animation, un déclencheur est nécessaire. Le seul but de ce widget est d’animer le changement d’alignement, il n’a donc que quelques propriétés : ajouter un enfant, définir son alignement, déclencher le changement d’alignement, et c’est tout.

_getAnimatedAlignWidget() { return AnimatedAlign(duration: Duration(seconds: 1),curve: Curves.easeInOut,alignment: alignTop ? Alignment.topLeft : Alignment.center,child: _getAnimatedCrossfade(), );}
Animation de l’alignement du widget nom. (Grand aperçu)

Il n’a que deux propriétés obligatoires :

  • child:
    L’enfant dont l’alignement sera modifié.
  • alignment:
    Valeur d’alignement requise.

Ce widget est vraiment simple mais les résultats sont élégants. De plus, nous avons vu avec quelle facilité nous pouvons utiliser deux widgets animés différents pour créer une animation plus complexe. C’est la beauté des widgets animés.

AnimatedPadding

Maintenant, nous avons le nom de l’utilisateur en haut, animé en douceur sans beaucoup d’efforts, en utilisant différents types de widgets animés. Ajoutons une salutation, « Hi », avant le nom. L’ajout d’un widget de texte avec la valeur « Hi, » en haut fera en sorte qu’il chevauche le widget de texte de salutation, ressemblant à l’image ci-dessous.

Les widgets de salutation et de nom se chevauchent. (Grand aperçu)

Et si le widget de texte de nom avait un certain padding à gauche ? Augmenter le padding à gauche fonctionnera certainement, mais attendez : pouvons-nous augmenter le padding avec une certaine animation ? Oui, et c’est ce que fait AnimatedPadding. Pour rendre tout cela beaucoup plus beau, faisons en sorte que le widget de texte de salutations s’estompe et que le rembourrage du widget de texte de nom augmente en même temps.

_getAnimatedPaddingWidget() { return AnimatedPadding( duration: Duration(seconds: 1), curve: Curves.fastOutSlowIn, padding: increaseLeftPadding ? EdgeInsets.only(left: 28.0) : EdgeInsets.only(left: 0), child: _getAnimatedCrossfade(), );}

Puisque l’animation ci-dessus devrait se produire seulement après que l’alignement animé précédent soit terminé, nous devons retarder le déclenchement de cette animation. En s’éloignant brièvement du sujet, c’est le bon moment pour parler d’un mécanisme populaire pour ajouter un délai. Flutter propose plusieurs techniques de ce type, mais le constructeur Future.delayed est l’une des approches les plus simples, les plus propres et les plus lisibles. Par exemple, pour exécuter un morceau de code après 1 seconde:

Future.delayed(Duration(seconds: 1), (){ sum = a + b; // This sum will be calculated after 1 second. print(sum);});

Puisque la durée du délai est déjà connue (calculée à partir des durées d’animation précédentes), l’animation peut être déclenchée après cet intervalle.

// Showing "Hi" after 1 second - greetings visibility trigger._showGreetings() { Future.delayed(Duration(seconds: 1), () { setState(() { showGreetings = true; }); });}// Increasing the padding for name label widget after 1 second - increase padding trigger._increaseLeftPadding() { Future.delayed(Duration(seconds: 1), () { setState(() { increaseLeftPadding = true; }); });}
Animation de remplissage du widget nom. (Grand aperçu)

Ce widget n’a que deux propriétés obligatoires:

  • child
    L’enfant à l’intérieur de ce widget, auquel le padding sera appliqué.
  • padding
    La quantité d’espace à ajouter.

AnimatedSize

Aujourd’hui, toute application ayant une certaine forme d’animation inclura un zoom avant ou arrière sur les composants visuels pour attirer l’attention de l’utilisateur (communément appelé animation de mise à l’échelle). Pourquoi ne pas utiliser la même technique ici ? Nous pouvons montrer à l’utilisateur une citation motivante qui zoome depuis le centre de l’écran. Laissez-moi vous présenter le widget AnimatedSize, qui active les effets de zoom avant et de zoom arrière, contrôlés par la modification de la taille de son enfant.

Ce widget est un peu différent des autres en ce qui concerne les paramètres requis. Nous avons besoin de ce que Flutter appelle un « Ticker ». Flutter a une méthode pour faire savoir aux objets chaque fois qu’un nouvel événement de trame est déclenché. On peut l’imaginer comme quelque chose qui envoie un signal disant « Fais-le maintenant ! … Faites-le maintenant ! … Faites-le maintenant ! … »

Le widget AnimatedSize nécessite une propriété – vsync – qui accepte un fournisseur de ticker. La façon la plus simple d’obtenir un fournisseur de téléscripteur est d’ajouter un Mixin à la classe. Il existe deux implémentations de base de fournisseur de téléscripteur : SingleTickerProviderStateMixin, qui fournit un seul ticker ; et TickerProviderStateMixin, qui en fournit plusieurs.

L’implémentation par défaut d’un ticker est utilisée pour marquer les images d’une animation. Dans ce cas, c’est cette dernière qui est employée. En savoir plus sur les mixins.

// Helper method to create quotes card widget._getQuoteCardWidget() { return Card( color: Colors.green, elevation: 8.0, child: _getAnimatedSizeWidget(), );}// Helper method to create animated size widget and set its properties._getAnimatedSizeWidget() { return AnimatedSize( duration: Duration(seconds: 1), curve: Curves.easeInOut, vsync: this, child: _getQuoteContainer(), );}// Helper method to create the quotes container widget with different sizes._getQuoteContainer() { return Container( height: showQuoteCard ? 100 : 0, width: showQuoteCard ? screenWidth - 32 : 0, child: Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: Text(quote, style: TextStyle(color: Colors.white, fontWeight: FontWeight.w400, fontSize: 14),), ), ), );}// Trigger used to show the quote card widget._showQuote() { Future.delayed(Duration(seconds: 2), () { setState(() { showQuoteCard = true; }); });}
Animation de mise à l’échelle du widget des citations. (Grand aperçu)

Propriétés obligatoires pour ce widget :

  • vsync
    Le fournisseur de téléscripteur requis pour coordonner l’animation et les changements de trame.<
  • child
    L’enfant dont les changements de taille seront animés.

L’animation de zoom avant et de zoom arrière est maintenant facilement apprivoisée.

AnimatedPositioned

Génial ! Les citations zooment depuis le centre pour attirer l’attention de l’utilisateur. Et si elles glissaient vers le haut depuis le bas tout en zoomant ? Essayons. Cette motion implique de jouer avec la position du widget de citation et d’animer les changements de propriétés de position. AnimatedPositioned est le candidat parfait.

Ce widget fait automatiquement transiter la position de l’enfant sur une durée donnée dès que la position spécifiée change. Un point à noter : il ne fonctionne que si son widget parent est un « Stack ». Ce widget est assez simple et direct à utiliser. Voyons voir.

// Helper method to create the animated positioned widget.// With position changes based on "showQuoteCard" flag._getAnimatedPositionWidget() { return AnimatedPositioned( duration: Duration(seconds: 1), curve: Curves.easeInOut, child: _getQuoteCardWidget(), top: showQuoteCard ? screenHeight/2 - 100 : screenHeight, left: !showQuoteCard ? screenWidth/2 : 12, );}
Position avec animation de mise à l’échelle des citations. (Grand aperçu)

Ce widget n’a qu’une seule propriété obligatoire:

  • child
    Le widget dont la position sera modifiée.

Si la taille de l’enfant n’est pas censée changer en même temps que sa position, une alternative plus performante à ce widget serait SlideTransition.

Voici notre animation complète:

Tous les widgets animés ensemble. (Grand aperçu)

Conclusion

Les animations font partie intégrante de l’expérience utilisateur. Les apps statiques ou les apps avec des animations bancales diminuent non seulement la rétention des utilisateurs mais aussi la réputation d’un développeur à fournir des résultats.

Aujourd’hui, la plupart des apps populaires ont une sorte d’animation subtile pour ravir les utilisateurs. Les réactions animées aux demandes des utilisateurs peuvent également les inciter à explorer davantage. Flutter offre beaucoup de fonctionnalités pour le développement multiplateforme, y compris un support riche pour des animations fluides et réactives.

Flutter a un grand support de plug-in qui nous permet d’utiliser les animations d’autres développeurs. Maintenant qu’il a mûri jusqu’à la version 1.9, avec tant d’amour de la part de la communauté, Flutter ne peut que s’améliorer à l’avenir. Je dirais que c’est le moment idéal pour apprendre Flutter!

Leave a Reply