Avez-vous une question? (216) 97 656 803 hajjriadh@gmail.com
Flutter

Les Animations Implicites dans Flutter

Un cours complet pour maîtriser Les Animations Implicites dans Flutter.

0 chapitres 0 QCM Accès gratuit
  1. Objectifs

    • Comprendre le concept des animations implicites
    • Savoir implémenter des animations implicites
    • Manipuler plusieurs propriétés animées simultanément
  2. Introduction aux Animations implicites

    • Les animations implicites dans Flutter sont des animations où le framework gère automatiquement la transition entre l'état initial et l'état final d'une propriété. Cela simplifie le processus d'animation, car il suffit de définir une nouvelle valeur de propriété, et Flutter se charge d'animer la transition de manière fluide.
  3. Animations Implicites :

      Les Animations Implicites dans Flutter

    • Concept : Les animations implicites sont des animations où le développeur définit uniquement la nouvelle valeur de la propriété à animer (comme la taille, la couleur, l'opacité, etc.), et Flutter se charge de calculer la transition entre l'état initial et l'état final de manière fluide.
    • Pourquoi implicite ? Elles sont dites implicites parce que les calculs d'interpolation entre l'état initial et l'état final sont faits par le framework automatiquement, sans besoin de gestion manuelle de l'animation ou du contrôle de chaque étape.
    • Certains widgets animés intégrés sont :
      • AnimatedAlign
      • AnimatedBuilder
      • AnimatedContainer
      • AnimatedOpacity
      • AnimatedPadding
      • AnimatedPositioned
      • AnimatedRotation
      • AnimatedScale
      • AnimatedSize
      • AnimatedSlide
      • AnimatedSwitcher
  4. Exemples de widgets d'animations implicites :

    1. AnimatedBuilder
      1. Description :

        • AnimatedBuilder est un widget qui vous permet d'utiliser n'importe quel widget pour créer des animations personnalisées. Il prend un Animation et un builder, et met à jour le widget à chaque changement d'animation.
        • Il est utilisé principalement pour réutiliser des widgets enfants sans avoir besoin de les recréer à chaque changement d'animation.
      2. Syntaxe :

          AnimatedBuilder({
            required Animation<T> animation,
            required Widget Function(BuildContext, Widget?) builder,
            Widget? child,
          });
      3. Exemple :

          class AnimatedBuilderExample extends StatefulWidget {
            @override
            _AnimatedBuilderExampleState createState() => _AnimatedBuilderExampleState();
          }
          
          class _AnimatedBuilderExampleState extends State with SingleTickerProviderStateMixin {
            late AnimationController _controller;
          
            @override
            void initState() {
              super.initState();
              _controller = AnimationController(
                duration: const Duration(seconds: 2),
                vsync: this,
              )..repeat(reverse: true);
            }
          
            @override
            Widget build(BuildContext context) {
              return AnimatedBuilder(
                animation: _controller,
                builder: (context, child) {
                  return Transform.rotate(
                    angle: _controller.value * 2.0 * 3.14,
                    child: child,
                  );
                },
                child: Container(width: 100, height: 100, color: Colors.blue),
              );
            }
          }
    2. AnimatedContainer
      1. Description :

        • Ce widget permet d'animer plusieurs propriétés telles que la taille, la couleur, la bordure, etc. Lorsque ces propriétés changent, Flutter anime la transition entre les anciennes et nouvelles valeurs.
        • AnimatedContainer anime les changements de ses propriétés telles que la taille, la couleur, la forme, les marges, etc. Vous pouvez modifier ces propriétés, et Flutter animera automatiquement la transition entre les anciennes et les nouvelles valeurs.
      2. Syntaxe :

          AnimatedContainer({
            required Duration duration,
            double? width,
            double? height,
            Color? color,
            BoxDecoration? decoration,
            EdgeInsetsGeometry? padding,
            Curve curve = Curves.linear,
            required Widget child,
          });
      3. Exemple :

          class AnimatedContainerExample extends StatefulWidget {
            @override
            _AnimatedContainerExampleState createState() => _AnimatedContainerExampleState();
          }
          
          class _AnimatedContainerExampleState extends State {
            bool _isExpanded = false;
          
            @override
            Widget build(BuildContext context) {
              return GestureDetector(
                onTap: () {
                  setState(() {
                    _isExpanded = !_isExpanded;
                  });
                },
                child: AnimatedContainer(
                  width: _isExpanded ? 200 : 100,
                  height: _isExpanded ? 200 : 100,
                  color: _isExpanded ? Colors.blue : Colors.red,
                  duration: Duration(seconds: 1),
                  curve: Curves.easeInOut,
                  child: Center(child: Text('Tap me!')),
                ),
              );
            }
          }
    3. AnimatedOpacity
      1. Description :

        • Ce widget anime l'opacité d'un widget, permettant de faire apparaître ou disparaître un élément progressivement.
        • AnimatedOpacity anime les changements d'opacité d'un widget. Vous pouvez modifier la valeur d'opacité entre 0.0 (totalement transparent) et 1.0 (totalement opaque), et Flutter animera la transition en douceur.
      2. Syntaxe :

          AnimatedOpacity({
            required double opacity,
            required Duration duration,
            Curve curve = Curves.linear,
            required Widget child,
          });
      3. Exemple :

          class AnimatedOpacityExample extends StatefulWidget {
            @override
            _AnimatedOpacityExampleState createState() => _AnimatedOpacityExampleState();
          }
          
          class _AnimatedOpacityExampleState extends State {
            double _opacity = 1.0;
          
            @override
            Widget build(BuildContext context) {
              return Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  AnimatedOpacity(
                    opacity: _opacity,
                    duration: Duration(seconds: 1),
                    child: Container(width: 100, height: 100, color: Colors.green),
                  ),
                  ElevatedButton(
                    onPressed: () {
                      setState(() {
                        _opacity = _opacity == 1.0 ? 0.0 : 1.0;
                      });
                    },
                    child: Text('Toggle Opacity'),
                  ),
                ],
              );
            }
          }
    4. AnimatedAlign
      1. Description :

        • Ce widget permet d'animer l'alignement d'un widget à l'intérieur de son conteneur.
        • AnimatedAlign anime l'alignement d'un widget à l'intérieur de son parent. Vous pouvez spécifier l'alignement (haut, bas, centre, etc.), et Flutter animera la transition entre les différentes positions.
      2. Syntaxe :

          AnimatedAlign({
            required Alignment alignment,
            required Duration duration,
            Curve curve = Curves.linear,
            required Widget child,
          });
      3. Exemple :

          class AnimatedAlignExample extends StatefulWidget {
            @override
            _AnimatedAlignExampleState createState() => _AnimatedAlignExampleState();
          }
          
          class _AnimatedAlignExampleState extends State {
            bool _isAligned = false;
          
            @override
            Widget build(BuildContext context) {
              return GestureDetector(
                onTap: () {
                  setState(() {
                    _isAligned = !_isAligned;
                  });
                },
                child: Container(
                  height: 300,
                  width: 300,
                  color: Colors.grey[300],
                  child: AnimatedAlign(
                    alignment: _isAligned ? Alignment.topRight : Alignment.bottomLeft,
                    duration: Duration(seconds: 1),
                    curve: Curves.easeInOut,
                    child: Container(width: 50, height: 50, color: Colors.blue),
                  ),
                ),
              );
            }
          }
    5. AnimatedPadding
      1. Description :

        • Ce widget anime les marges internes (padding) d'un widget lorsque ces valeurs changent.
        • AnimatedPadding anime les changements de padding (espacement) autour d'un widget. Vous pouvez modifier les valeurs de padding, et Flutter animera la transition.
      2. Syntaxe :

          AnimatedPadding({
            required EdgeInsetsGeometry padding,
            required Duration duration,
            Curve curve = Curves.linear,
            required Widget child,
          });
      3. Exemple :

          class AnimatedPaddingExample extends StatefulWidget {
            @override
            _AnimatedPaddingExampleState createState() => _AnimatedPaddingExampleState();
          }
          
          class _AnimatedPaddingExampleState extends State {
            double _paddingValue = 10.0;
          
            @override
            Widget build(BuildContext context) {
              return Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  AnimatedPadding(
                    padding: EdgeInsets.all(_paddingValue),
                    duration: Duration(seconds: 1),
                    curve: Curves.easeInOut,
                    child: Container(width: 100, height: 100, color: Colors.red),
                  ),
                  ElevatedButton(
                    onPressed: () {
                      setState(() {
                        _paddingValue = _paddingValue == 10.0 ? 50.0 : 10.0;
                      });
                    },
                    child: Text('Change Padding'),
                  ),
                ],
              );
            }
          }
    6. AnimatedPositioned
      1. Description :

        • AnimatedPositioned anime la position d'un widget dans un Stack quand la position change.
        • Idéal pour animer des mouvements dans une interface.
      2. Syntaxe :

          AnimatedPositioned({
            required Widget child,
            required Duration duration,
            double? left,
            double? top,
            double? right,
            double? bottom,
            Curve curve = Curves.linear,
          });
      3. Exemple :

          class AnimatedPositionedExample extends StatefulWidget {
            @override
            _AnimatedPositionedExampleState createState() => _AnimatedPositionedExampleState();
          }
          
          class _AnimatedPositionedExampleState extends State {
            bool _isMoved = false;
          
            @override
            Widget build(BuildContext context) {
              return Stack(
                children: [
                  AnimatedPositioned(
                    duration: Duration(seconds: 2),
                    left: _isMoved ? 150 : 50,
                    top: _isMoved ? 200 : 50,
                    child: GestureDetector(
                      onTap: () {
                        setState(() {
                          _isMoved = !_isMoved;
                        });
                      },
                      child: Container(width: 100, height: 100, color: Colors.red),
                    ),
                  ),
                ],
              );
            }
          }
    7. AnimatedRotation
      1. Description :

        • AnimatedRotation anime la rotation d'un widget en fonction d'une valeur d'angle spécifiée en radians.
      2. Syntaxe :

          AnimatedRotation({
            required double turns,
            required Duration duration,
            Curve curve = Curves.linear,
            required Widget child,
          });
      3. Exemple :

          AnimatedRotation(
            turns: 0.5, // 180-degree rotation
            duration: Duration(seconds: 1),
            child: Icon(Icons.rotate_right, size: 100),
          );
    8. AnimatedScale
      1. Description :

        • AnimatedScale anime le changement de taille (zoom) d'un widget en fonction d'un facteur de mise à l'échelle.
      2. Syntaxe :

          AnimatedScale({
            required double scale,
            required Duration duration,
            Curve curve = Curves.linear,
            required Widget child,
          });
      3. Exemple :

          AnimatedScale(
            scale: 1.5, // Increases size by 1.5x
            duration: Duration(seconds: 1),
            child: Container(width: 100, height: 100, color: Colors.blue),
          );
    9. AnimatedSize
      1. Description :

        • AnimatedSize anime le changement de taille d'un widget lorsque sa taille change.
        • Nécessite l'ajout de vsync: this dans l'état du widget.
      2. Syntaxe :

          AnimatedSize({
            required Widget child,
            required Duration duration,
            Curve curve = Curves.linear,
            required TickerProvider vsync,
          });
      3. Exemple :

          class AnimatedSizeExample extends StatefulWidget {
            @override
            _AnimatedSizeExampleState createState() => _AnimatedSizeExampleState();
          }
          
          class _AnimatedSizeExampleState extends State with TickerProviderStateMixin {
            bool _isExpanded = false;
          
            @override
            Widget build(BuildContext context) {
              return GestureDetector(
                onTap: () {
                  setState(() {
                    _isExpanded = !_isExpanded;
                  });
                },
                child: AnimatedSize(
                  duration: Duration(seconds: 1),
                  vsync: this,
                  child: Container(
                    width: 100,
                    height: _isExpanded ? 200 : 100,
                    color: Colors.green,
                  ),
                ),
              );
            }
          }
    10. AnimatedSlide
      1. Description :

        • AnimatedSlide anime la position d'un widget sur un axe cartésien (x, y), où chaque valeur est un pourcentage de la taille de l'écran.
      2. Syntaxe :

          AnimatedSlide({
            required Offset offset,
            required Duration duration,
            Curve curve = Curves.linear,
            required Widget child,
          });
      3. Exemple :

            AnimatedSlide(
              offset: Offset(0.2, 0.0), // Move 20% of the screen width to the right
              duration: Duration(seconds: 1),
              child: Container(width: 100, height: 100, color: Colors.orange),
            );
    11. AnimatedSwitcher
      1. Description :

        • AnimatedSwitcher permet d'animer la transition entre différents widgets enfants. Lorsque le widget enfant change, AnimatedSwitcher anime l'ajout du nouveau widget et la suppression de l'ancien.
      2. Syntaxe :

          AnimatedSwitcher({
            required Widget child,
            required Duration duration,
            Curve switchInCurve = Curves.linear,
            Curve switchOutCurve = Curves.linear,
            required AnimatedSwitcherTransitionBuilder transitionBuilder,
          });
      3. Exemple :

          class AnimatedSwitcherExample extends StatefulWidget {
            @override
            _AnimatedSwitcherExampleState createState() => _AnimatedSwitcherExampleState();
          }
          
          class _AnimatedSwitcherExampleState extends State {
            int _count = 0;
          
            @override
            Widget build(BuildContext context) {
              return Column(
                children: [
                  AnimatedSwitcher(
                    duration: Duration(seconds: 1),
                    child: Text(
                      '$_count',
                      key: ValueKey(_count),
                      style: TextStyle(fontSize: 50),
                    ),
                  ),
                  ElevatedButton(
                    onPressed: () {
                      setState(() {
                        _count++;
                      });
                    },
                    child: Text('Increment'),
                  ),
                ],
              );
            }
          }
  5. Applications

    1. 01 Exercice: 01

      • Enoncé:
        • Objectif : L’objectif de cet exercice est de permettre à l’étudiant d’apprendre à utiliser des animations implicites dans Flutter à travers des widgets comme AnimatedContainer, AnimatedOpacity, AnimatedAlign, et AnimatedPadding. L’étudiant devra combiner ces widgets pour créer une interface réactive et animée.
        • Consignes :
          • Créez une application Flutter qui contient une carte (Card) centrée à l'écran.
          • La carte devra :
            • Changer de taille lorsqu'on appuie dessus.
            • Modifier son alignement (se déplacer d'un coin à l'autre de l'écran).
            • Changer son opacité (de totalement opaque à semi-transparent).
            • Ajuster son padding pour laisser plus ou moins d'espace autour d’elle.
          • L’étudiant devra utiliser :
            • AnimatedContainer pour la taille et la couleur.
            • AnimatedOpacity pour la transparence.
            • AnimatedAlign pour l’alignement.
            • AnimatedPadding pour les marges autour de la carte.
            • L’animation doit être déclenchée par un tap sur la carte.
          Solution
            import 'package:flutter/material.dart';
            
            void main() {
              runApp(AnimatedCardApp());
            }
            
            class AnimatedCardApp extends StatelessWidget {
              @override
              Widget build(BuildContext context) {
                return MaterialApp(
                  home: AnimatedCardScreen(),
                );
              }
            }
            
            class AnimatedCardScreen extends StatefulWidget {
              @override
              _AnimatedCardScreenState createState() => _AnimatedCardScreenState();
            }
            
            class _AnimatedCardScreenState extends State {
              bool _isExpanded = false;
              bool _isAlignedTopRight = false;
              double _opacity = 1.0;
              double _paddingValue = 10.0;
            
              @override
              Widget build(BuildContext context) {
                return Scaffold(
                  appBar: AppBar(
                    title: Text("Exercice d'animation"),
                  ),
                  body: GestureDetector(
                    onTap: () {
                      setState(() {
                        _isExpanded = !_isExpanded;
                        _isAlignedTopRight = !_isAlignedTopRight;
                        _opacity = _opacity == 1.0 ? 0.5 : 1.0;
                        _paddingValue = _paddingValue == 10.0 ? 50.0 : 10.0;
                      });
                    },
                    child: AnimatedPadding(
                      padding: EdgeInsets.all(_paddingValue),
                      duration: Duration(seconds: 1),
                      curve: Curves.easeInOut,
                      child: AnimatedAlign(
                        alignment: _isAlignedTopRight ? Alignment.topRight : Alignment.bottomLeft,
                        duration: Duration(seconds: 1),
                        curve: Curves.easeInOut,
                        child: AnimatedOpacity(
                          opacity: _opacity,
                          duration: Duration(seconds: 1),
                          child: AnimatedContainer(
                            width: _isExpanded ? 200 : 100,
                            height: _isExpanded ? 200 : 100,
                            color: _isExpanded ? Colors.blue : Colors.red,
                            duration: Duration(seconds: 1),
                            curve: Curves.easeInOut,
                            child: Center(child: Text('Tap me!')),
                          ),
                        ),
                      ),
                    ),
                  ),
                );
              }
            }
    2. Exercice_02 : Création d’un bouton animé avec AnimatedContainer
      • Enoncé:
        • Animer un bouton Flutter qui change de taille, de couleur, et de bordure lorsqu’il est cliqué. Créez un bouton au centre de l’écran. Lorsqu'un utilisateur clique sur le bouton, la taille doit doubler, sa couleur doit changer, et ses bordures doivent devenir arrondies. Utilisez AnimatedContainer pour gérer les transitions entre les différentes propriétés du bouton.
        • Utilisez un AnimatedContainer pour définir la taille, la couleur et la bordure du bouton, et employez setState pour modifier les propriétés à animer lors du clic sur le bouton. Ajoutez des courbes d'animation comme Curves.easeIn ou Curves.bounceOut pour observer leur effet sur les transitions.
        Solution
          import 'package:flutter/material.dart';
          
          void main() {
            runApp(MyApp());
          }
          
          class MyApp extends StatelessWidget {
            @override
            Widget build(BuildContext context) {
              return MaterialApp(
                home: AnimatedButtonScreen(),
              );
            }
          }
          
          class AnimatedButtonScreen extends StatefulWidget {
            @override
            _AnimatedButtonScreenState createState() => _AnimatedButtonScreenState();
          }
          
          class _AnimatedButtonScreenState extends State {
            double _width = 100;
            double _height = 50;
            Color _color = Colors.blue;
            BorderRadiusGeometry _borderRadius = BorderRadius.circular(8);
          
            void _animateButton() {
              setState(() {
                // Toggle between two states
                _width = _width == 100 ? 200 : 100;
                _height = _height == 50 ? 100 : 50;
                _color = _color == Colors.blue ? Colors.red : Colors.blue;
                _borderRadius = _borderRadius == BorderRadius.circular(8)
                    ? BorderRadius.circular(30)
                    : BorderRadius.circular(8);
              });
            }
          
            @override
            Widget build(BuildContext context) {
              return Scaffold(
                appBar: AppBar(title: Text('Animated Button Example')),
                body: Center(
                  child: AnimatedContainer(
                    width: _width,
                    height: _height,
                    decoration: BoxDecoration(
                      color: _color,
                      borderRadius: _borderRadius,
                    ),
                    duration: Duration(seconds: 1),
                    curve: Curves.easeIn, // You can change to Curves.bounceOut or others
                    child: TextButton(
                      onPressed: _animateButton,
                      child: Text(
                        'Click Me',
                        style: TextStyle(color: Colors.white, fontSize: 18),
                      ),
                    ),
                  ),
                ),
              );
            }
          }
    3. Exercice_03 : Transition de l'opacité avec AnimatedOpacity
      • Enoncé:
        • Créer une animation Flutter qui masque et révèle un widget en douceur.
          • Ajoutez un texte ou une image à l’écran.
          • Utilisez AnimatedOpacity pour faire disparaître et réapparaître le widget lorsque l’utilisateur clique sur un bouton.
          • L’opacité doit passer de 1 (complètement visible) à 0 (invisible) en douceur.
          • Utilisez un AnimatedOpacity pour contrôler la transparence du widget.
          • Associez un bouton pour déclencher l’animation avec un setState qui change l’opacité.
          • Expérimentez avec la durée de l’animation pour obtenir différents effets de fluidité.
        Solution
          import 'package:flutter/material.dart';
          
          void main() {
            runApp(MyApp());
          }
          
          class MyApp extends StatelessWidget {
            @override
            Widget build(BuildContext context) {
              return MaterialApp(
                home: AnimatedOpacityExample(),
              );
            }
          }
          
          class AnimatedOpacityExample extends StatefulWidget {
            @override
            _AnimatedOpacityExampleState createState() => _AnimatedOpacityExampleState();
          }
          
          class _AnimatedOpacityExampleState extends State {
            // Propriété d'opacité
            double _opacity = 1.0;
          
            // Fonction pour changer l'opacité
            void _toggleOpacity() {
              setState(() {
                // Alterne entre 1 (visible) et 0 (invisible)
                _opacity = _opacity == 1.0 ? 0.0 : 1.0;
              });
            }
          
            @override
            Widget build(BuildContext context) {
              return Scaffold(
                appBar: AppBar(
                  title: Text('Animation Opacity'),
                ),
                body: Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      // AnimatedOpacity pour animer la visibilité
                      AnimatedOpacity(
                        opacity: _opacity,  // Gère la transparence du widget
                        duration: Duration(seconds: 2),  // Durée de l'animation
                        curve: Curves.easeInOut,  // Courbe de l'animation
                        child: Container(
                          width: 200,
                          height: 200,
                          color: Colors.blue,
                          child: Center(
                            child: Text(
                              'Hello!',
                              style: TextStyle(
                                fontSize: 28,
                                color: Colors.white,
                              ),
                            ),
                          ),
                        ),
                      ),
                      SizedBox(height: 20),
                      // Bouton pour déclencher l'animation
                      ElevatedButton(
                        onPressed: _toggleOpacity,
                        child: Text('Masquer / Révéler'),
                      ),
                    ],
                  ),
                ),
              );
            }
          }
          
    4. Exercice_04 : Création d'une boîte qui change de position avec AnimatedPositioned
      • Enoncé:
        • Créez un widget positionné (Positioned) dans un Stack. Lorsque l’utilisateur appuie sur un bouton, la boîte doit se déplacer vers une nouvelle position à l’aide de AnimatedPositioned.
        • Utilisez Stack pour organiser plusieurs widgets avec des positions définies. Modifiez les propriétés left, right, top, et bottom de la boîte lorsque l’utilisateur interagit.
        • Employez AnimatedPositioned pour que le changement de position se fasse en douceur.
      Solution
        import 'package:flutter/material.dart';
        
        void main() {
          runApp(MyApp());
        }
        
        class MyApp extends StatelessWidget {
          @override
          Widget build(BuildContext context) {
            return MaterialApp(
              home: Scaffold(
                appBar: AppBar(title: Text('Déplacer une boîte')),
                body: MovingBox(),
              ),
            );
          }
        }
        
        class MovingBox extends StatefulWidget {
          @override
          _MovingBoxState createState() => _MovingBoxState();
        }
        
        class _MovingBoxState extends State {
          double _left = 50;
          double _top = 50;
        
          void _moveBox() {
            setState(() {
              // Modifiez les coordonnées pour déplacer la boîte
              _left = _left == 50 ? 200 : 50;
              _top = _top == 50 ? 200 : 50;
            });
          }
        
          @override
          Widget build(BuildContext context) {
            return Stack(
              children: [
                AnimatedPositioned(
                  duration: Duration(seconds: 1),
                  left: _left,
                  top: _top,
                  child: Container(
                    width: 100,
                    height: 100,
                    color: Colors.blue,
                  ),
                ),
                Positioned(
                  bottom: 30,
                  left: 30,
                  child: ElevatedButton(
                    onPressed: _moveBox,
                    child: Text('Déplacer la boîte'),
                  ),
                ),
              ],
            );
          }
        }
    5. Exercice_05 :
      • Enoncé:
        Solution