Créer des animations dans Flutter
Créer des animations dans Flutter
-
Objectif du Tutoriel
-
Introduction aux animations dans Flutter
- Flutter propose plusieurs types d’animations, notamment :
- Animations implicites : Faciles à utiliser, elles permettent de modifier les propriétés des widgets avec des transitions douces.
- Animations explicites : Donnent plus de contrôle pour des animations complexes grâce à des objets comme AnimationController.
-
Préparation de l’environnement
- Assurez-vous que votre environnement Flutter est configuré correctement. Créez un nouveau projet en exécutant la commande suivante dans votre terminal :
flutter create animation_demo
- Accédez au dossier :
cd animation_demo
- Ouvrez le projet dans votre éditeur préféré, comme VS Code ou Android Studio.
-
Création d’animations implicites
- Les animations implicites sont créées grâce à des widgets qui gèrent déjà certaines animations pour vous, car ils implémentent la classe ImplicitlyAnimatedWidget. Il s’agit d’une classe qui anime les changements de propriétés. Par exemple, si un AnimatedContainer voit sa propriété largeur changer, la reconstruction ne se fera pas en un coup comme habituellement, mais en plusieurs fois afin de créer une animation qui se charge de la transition entre l’état initial et le nouvel état.
- Flutter possède une série de widgets, qui sont simplement des versions animées de widgets déjà existants. Ces widgets créent une animation à chaque fois qu’une des propriétés du widget change et se nomment (entre autres) les AnimatedFoo.
- Liste des AnimatedFoo :
- AnimatedContainer
- AnimatedAlign
- AnimatedDefaultTextStyle
- AnimatedOpacity
- AnimatedPadding
- AnimatedPhysicalModel
- AnimatedPositioned
- AnimatedPositionedDirectional
- Explication :
AnimatedContainer
: Gère automatiquement la transition de ses propriétés comme la taille, la couleur, etc.Duration
: Définit la durée de l’animation.Curve
: Ajoute une courbe pour personnaliser le comportement de l’animation.- Explication :
- Cet exemple illustre comment utiliser un widget AnimatedContainer pour animer plusieurs propriétés d’un conteneur telles que la couleur, la hauteur et la largeur. L’animation est déclenchée par un bouton qui modifie l’état du conteneur.
- Déclaration des variables d’état :
_isContainerExpanded
: Contrôle si le conteneur est agrandi ou non._containerColor, _containerHeight, _containerWidth
: Ces variables définissent les propriétés du conteneur et changent en fonction de l’état.- Animation avec AnimatedContainer :
- Le widget AnimatedContainer permet de changer ses propriétés avec une transition animée.
- Les propriétés modifiées sont :
Couleur (color)
: Change entre Colors.blue et Colors.green.Hauteur (height) et Largeur (width)
: Augmentent ou diminuent.- Bouton d’interaction :
- Le bouton ElevatedButton déclenche la méthode _toggleAnimation, qui met à jour les propriétés du conteneur via setState().
- Cela entraîne un redessin du widget avec des transitions douces définies par AnimatedContainer.
- Personnalisation de l’animation :
Duration
: Définit la durée de l’animation (1 seconde ici).Curve
: Ajoute une courbe d’animation (Curves.easeInOut), rendant la transition plus fluide.-
Création d’animations explicites
- Explication :
AnimationController
: Contrôle l’animation, comme sa durée et son état.Tween
: Définit la plage de valeurs entre le début et la fin.CurvedAnimation
: Ajoute une courbe à l’animation.AnimatedBuilder
: Optimise le rendu en reconstruisant uniquement la partie animée.-
Animation combinée
- Explication :
Transform.rotate
: Applique une rotation.Opacity
: Modifie la transparence.- Les deux sont combinés pour un effet fluide.
-
Animation avancée avec des packages
- Flutter propose des bibliothèques pour simplifier les animations complexes :
flutter_animate
: Simple et puissant pour les animations.rive
: Pour des animations vectorielles interactives.lottie
: Pour lire des animations JSON créées avec After Effects.- Ajoutez un package dans pubspec.yaml
-
Bonnes pratiques
- Utilisez les animations uniquement lorsque cela améliore l’expérience utilisateur.
- Testez les performances, surtout sur des appareils bas de gamme.
- Préférez les animations implicites pour les besoins simples.
Exemple 1 : Changement de couleur avec AnimatedContainer
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: AnimationDemo(),
);
}
}
class AnimationDemo extends StatefulWidget {
@override
_AnimationDemoState createState() => _AnimationDemoState();
}
class _AnimationDemoState extends State {
bool isSelected = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Animation Implicite')),
body: Center(
child: GestureDetector(
onTap: () {
setState(() {
isSelected = !isSelected;
});
},
child: AnimatedContainer(
duration: Duration(seconds: 1),
width: isSelected ? 200.0 : 100.0,
height: isSelected ? 100.0 : 200.0,
color: isSelected ? Colors.blue : Colors.red,
curve: Curves.easeInOut,
),
),
),
);
}
}
Exemple 2 : Animation d’un Container avec AnimatedContainer
dans Flutter
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
// Define some variables to control the animation.
bool _isContainerExpanded = false;
Color _containerColor = Colors.blue;
double _containerHeight = 100.0;
double _containerWidth = 100.0;
// Function to toggle the animation.
void _toggleAnimation() {
setState(() {
_isContainerExpanded = !_isContainerExpanded;
// Update color, height, and width based on the animation state.
_containerColor = _isContainerExpanded ? Colors.green : Colors.blue;
_containerHeight = _isContainerExpanded ? 200.0 : 100.0;
_containerWidth = _isContainerExpanded ? 200.0 : 100.0;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('AnimatedContainer Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// AnimatedContainer with changing color, height, and width.
AnimatedContainer(
duration: Duration(seconds: 1), // Animation duration.
curve: Curves.easeInOut, // Animation curve.
color: _containerColor, // Color that changes.
height: _containerHeight, // Height that changes.
width: _containerWidth, // Width that changes.
child: Center(
child: Text(
'Tap me!',
style: TextStyle(color: Colors.white),
),
),
),
SizedBox(height: 20.0),
// Button to trigger the animation.
ElevatedButton(
onPressed: _toggleAnimation,
child: Text('Toggle Animation'),
),
],
),
),
);
}
}
Exemple 2 : Animation avec AnimationController et Tween
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: AnimationControllerDemo(),
);
}
}
class AnimationControllerDemo extends StatefulWidget {
@override
_AnimationControllerDemoState createState() =>
_AnimationControllerDemoState();
}
class _AnimationControllerDemoState extends State
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
_animation = Tween(begin: 50.0, end: 200.0).animate(
CurvedAnimation(parent: _controller, curve: Curves.bounceIn),
);
_controller.repeat(reverse: true);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Animation Explicite')),
body: Center(
child: AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Container(
width: _animation.value,
height: _animation.value,
color: Colors.green,
);
},
),
),
);
}
}
Exemple 3 : Rotation et Opacité
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: CombinedAnimationDemo(),
);
}
}
class CombinedAnimationDemo extends StatefulWidget {
@override
_CombinedAnimationDemoState createState() => _CombinedAnimationDemoState();
}
class _CombinedAnimationDemoState extends State
with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Animation Combinée')),
body: Center(
child: AnimatedBuilder(
animation: _controller,
child: Container(
width: 100.0,
height: 100.0,
color: Colors.purple,
),
builder: (context, child) {
return Transform.rotate(
angle: _controller.value * 2.0 * 3.14,
child: Opacity(
opacity: _controller.value,
child: child,
),
);
},
),
),
);
}
}
dependencies:
flutter_animate: ^4.0.0
Exemple avec flutter_animate
import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Animation avec Flutter Animate')),
body: Center(
child: Text('Bonjour Flutter!')
.animate()
.fadeIn(duration: 1000.ms)
.scale(),
),
),
);
}
}