Android a une caractéristique très intéressante de l'animation de vue appelée CircularRevealAnimation
- littéralement «divulgation circulaire». Flutter, à son tour, bien qu'il ait de riches capacités pour animer des widgets, ne fournit pas une telle animation hors de la boîte.

Cet article montrera comment implémenter une telle animation à l'aide de Flutter et publier la bibliothèque sur pub.dev pour un accès et une distribution faciles.
Implémentation d'animation
Dans Flutter, tout est un widget. Et l'animation ne fait pas exception. Par conséquent, nous créons la classe CircularRevealAnimation
, qui étendra la classe StatelessWidget
.
Le démarrage, l'arrêt et d'autres contrôles d'animation se font à l'aide de AnimationController
. Pour créer un AnimationController
vous devez hériter de StatefulWidget
et ajouter une classe spéciale SingleTickerProviderStateMixin
à State
.
Notre classe d'animation CircularRevealAnimation
ne gérera pas indépendamment l'animation, mais recevra Animation<double>
comme paramètre constructeur obligatoire, il n'est donc pas nécessaire d'hériter de StatefulWidget
. Ceci est fait pour que CircularRevealAnimation
puisse être facilement combiné avec d'autres animations qui utilisent le même AnimationController
. Par exemple, combinez l'animation de divulgation avec l'animation de changement de transparence.
Un autre paramètre important du constructeur CircularRevealAnimation
est child
, qui est un widget enfant de notre animation, et qui apparaîtra ou disparaîtra. En général, dans Flutter, de nombreux widgets ont un paramètre child
. Ces widgets vous permettent de modifier le comportement, le rendu ou la disposition d'un widget enfant. Ou ajoutez une animation, comme cela se produit avec CircularRevealAnimation
.
De plus, pour spécifier l'animation, des paramètres tels que le centre de l'ouverture (ou de la fermeture) de l'animation, ainsi que le rayon minimum et maximum de l'ouverture, seront requis. Ces paramètres sont facultatifs et peuvent être spécifiés comme null
ou non spécifiés lors de la création d'une animation. Dans ce cas, les valeurs par défaut seront utilisées: le centre de divulgation sera au centre du widget, le rayon minimum sera blessé à zéro et le rayon maximum sera égal à la distance du centre de divulgation au sommet du widget le plus éloigné du centre de divulgation.
L'algorithme de calcul de rayon maximal par défaut est le suivant. Tout d'abord, les distances horizontales et verticales du centre au sommet le plus éloigné du centre de divulgation sont calculées, puis la diagonale est calculée par le théorème de Pythagore.
static double calcMaxRadius(Size size, Offset center) { final w = max(center.dx, size.width - center.dx); final h = max(center.dy, size.height - center.dy); return sqrt(w * w + h * h); }
Vous devez maintenant implémenter le recadrage du widget dans le cercle pendant le rendu. La classe ClipPath
nous y aidera, ce qui vous permet de recadrer le widget selon un modèle arbitraire. En tant que paramètres, ce widget est passé clipper
(à ce sujet un peu plus tard) et child
est le widget enfant qui doit être recadré.
Le paramètre clipper
du widget ClipPath
détermine comment le widget enfant sera rogné. Pour créer votre propre modèle de recadrage, créez la classe CircularRevealClipper
qui hérite de la classe CustomClipper<Path>
et redéfinissez la Path getClip(Size size)
. Cette méthode renvoie un Path
délimitant la zone de recadrage. Dans notre cas, cette région est un cercle de centre donné. Pour calculer le rayon d'un cercle, vous devez connaître la valeur actuelle de l'animation. Cette valeur est transmise à CircularRevealClipper
comme paramètre de fraction
. Le rayon du cercle est calculé en utilisant une interpolation linéaire entre les rayons minimum et maximum.
Après cela, passons à l'implémentation du widget. Il est pratique d'utiliser AnimatedBuilder
pour créer une animation. Le constructeur AnimatedBuilder
accepte l'objet Animation<double>
et le builder
utilisés pour créer des widgets en fonction de la valeur d'animation actuelle. Dans le builder
nous créons un ClipPath
et passons la valeur actuelle de l'animation ( fraction
) au CircularRevealClipper
.
class CircularRevealAnimation extends StatelessWidget { ... @override Widget build(BuildContext context) { return AnimatedBuilder( animation: animation, builder: (BuildContext context, Widget _) { return ClipPath( clipper: CircularRevealClipper( fraction: animation.value, center: center, minRadius: minRadius, maxRadius: maxRadius, ), child: this.child, ); }, ); } }
Ceci termine la création de CircularRevealAnimation
. Reste à l'utiliser. Pour ce faire, créez un StatefulWidget
, AnimationController
et passez le AnimationController
à CircularRevealAnimation
.
Exemple d'utilisation import 'package:flutter/material.dart'; import 'package:circular_reveal_animation/circular_reveal_animation.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'CRA Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin { AnimationController animationController; Animation<double> animation; @override void initState() { super.initState(); animationController = AnimationController( vsync: this, duration: Duration(milliseconds: 1000), ); animation = CurvedAnimation( parent: animationController, curve: Curves.easeIn, ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("CRA Demo"), ), body: Padding( padding: const EdgeInsets.all(16.0), child: CircularRevealAnimation( minRadius: 12, maxRadius: 200, center: Offset(0, 300), child: Container(color: Colors.red), animation: animation, ), ), floatingActionButton: FloatingActionButton(onPressed: () { if (animationController.status == AnimationStatus.forward || animationController.status == AnimationStatus.completed) { animationController.reverse(); } else { animationController.forward(); } }), ); } }
Application de démonstration Github .
Création de bibliothèque
Pour créer une bibliothèque Dart ou Flutter, vous devez ajouter le fichier pubspec.yaml
au même répertoire que le répertoire lib
avec les fichiers Dart. Ce fichier contient une description de la bibliothèque, des informations sur les auteurs et les dépendances.
Il est également recommandé de créer un fichier définissant une API publique. Ce fichier se trouve dans le dossier lib
et comprend le nom de la bibliothèque et une liste de fichiers qui doivent être inclus dans l'API publique. Tous les autres fichiers Dart sont placés dans le répertoire src
. Cela masque non seulement les fichiers qui ne sont pas inclus dans l'API publique, mais vous permet également d'importer la bibliothèque à l'aide d'une seule expression d' import
. Le contenu de ce fichier :
library circular_reveal_animation; export 'package:circular_reveal_animation/src/circular_reveal_animation.dart';
Vous pouvez en savoir plus sur la création de bibliothèques sur Dart ici .
La publication d'une bibliothèque Dart dans pub.dev est très simple. Il vous suffit d'exécuter la commande flutter packages pub publish
partir du répertoire racine de la bibliothèque. La publication est effectuée pour le compte d'un compte Google, donc pendant le processus de publication un lien sera donné qui doit être ouvert dans un navigateur et connecté à Google. Par la suite, les mises à jour ne peuvent être publiées qu'en utilisant le compte pour le compte duquel la première version a été publiée.
Avant la publication, il est recommandé de vérifier que la bibliothèque est correcte à l'aide de la commande flutter packages pub publish --dry-run
.
Après l'exécution des flutter packages pub publish
bibliothèque sera immédiatement disponible sur pub.dev. Et, comme le dit la documentation, «la publication est éternelle» - plus tard, vous ne pourrez télécharger que de nouvelles versions. Des versions plus anciennes seront également disponibles.
Bien que la publication de bibliothèque semble simple, elle peut également présenter des pièges. Par exemple, lors de la publication de la première version, j'ai été retiré de quelques points de la note car la description de la bibliothèque (dans pubspec.yaml
) était trop courte.
Vous pouvez en savoir plus sur la publication de bibliothèques ici .
En fait, la bibliothèque circular_reveal_animation
sur pub.dev et github.com .
PS: J'ai utilisé ```java {...} ```
pour mettre en évidence le code Dart. Ce serait bien d'ajouter du code Dart surligné sur habr.com.