Advanced Animation Techniques For Flutter: A Guide
Published: 2024-04-12 12:04:15

by [David Ajanaku](https://blog.openreplay.com/authors/david-ajanaku)



<blockquote><em>
Animations play a crucial role in enhancing the user experience and improving an application's UI's overall look and feel. They help convey changes, transitions, and interactions more engagingly and intuitively. They can make your app feel more responsive, provide visual feedback to user actions, guide users' attention, and create a more polished and professional appearance. This article will show you ways to create great animations in Flutter.
</em></blockquote>


<div style="background-color:#efefef; border-radius:8px; padding:10px; display:block;">
<hr/>
<h3><em>Session Replay for Developers</em></h3> 
<p><em>Uncover frustrations, understand bugs and fix slowdowns like never before with <strong><a href="https://github.com/openreplay/openreplay" target="_blank">OpenReplay</a></strong> — an open-source session replay suite for developers. It can be <strong>self-hosted</strong> in minutes, giving you complete control over your customer data.</em></p>
<img alt="OpenReplay" style="margin-top:5px; margin-bottom:5px;" width="768" height="400" src="https://raw.githubusercontent.com/openreplay/openreplay/main/static/openreplay-git-hero.svg" class="astro-UXNKDZ4E" loading="lazy" decoding="async">
<p><em>Happy debugging! <a href="https://openreplay.com" target="_blank">Try using OpenReplay today.</a></em><p>
<hr/>
</div>



[Flutter](https://flutter-ko.dev/get-started/install) is an open-source UI software development kit created by Google. It is used to develop applications for [Android](https://docs.flutter.dev/get-started/flutter-for/android-devs), [iOS](https://docs.flutter.dev/deployment/ios), [Linux](https://docs.flutter.dev/platform-integration/linux/building), [Mac](https://docs.flutter.dev/get-started/install/macos/mobile-android), [Windows](https://docs.flutter.dev/get-started/install/windows/mobile), and the [web](https://docs.flutter.dev/platform-integration/web/building) from a single codebase. Flutter uses the [Dart](https://dart.dev/language) programming language and follows a [reactive programming](https://www.techtarget.com/searchapparchitecture/definition/reactive-programming) paradigm. It provides a rich set of pre-built and customizable widgets and a powerful framework for building beautiful, fluid User Interfaces(UI).
  
## Animations in Flutter

In Flutter, animations are controlled by an `AnimationController` object, which manages the animation's duration, status (e.g., playing, paused, completed), and forward or reverse playback. The `AnimationController` is connected to an [Animation](https://pub.dev/packages/animations) object, which generates a series of values over time (e.g., numbers, colors, sizes) that can be used to update the UI.

Below are some key classes that are frequently used in creating animations in Flutter:
* **Tween:** A [Tween](https://api.flutter.dev/flutter/animation/Tween-class.html) defines a range of values for `interpolation` in an animation. For example, a `Tween<double>` can define a range of double values, while a `Tween<Color>` can define a range of colors.
* **AnimationController:** [AnimationController](https://api.flutter.dev/flutter/animation/AnimationController-class.html) controls the animation process, including its duration, status, and playback direction. It is typically used with an `Animation` object to update the UI based on the animation's current value.
* **AnimatedBuilder:** An [AnimatedBuilder](https://api.flutter.dev/flutter/widgets/AnimatedBuilder-class.html) widget is used to rebuild itself whenever the animation changes. It is useful for encapsulating complex UI animations that require updating multiple widgets.
* **Curve:**  A [Curve](https://api.flutter.dev/flutter/animation/Curve-class.html) is used to dictate an animation's progression rate. Flutter provides several built-in curve types, such as `Curves.linear`, `Curves.easeIn`, `Curves.easeOut`, and `Curves.easeInOut`, among others.
    

## Setting Up Animations In Flutter
To set up animations in Flutter, you typically create an `AnimationController` and configure it with duration and optional settings such as initial value, `lower bound`, and `upper bound`. You then create an `Animation` object by chaining the `AnimationController` with a `Tween` or `Curve`, which defines the range of values or the progression rate of the animation. Finally, you can use the [addListener](https://api.flutter.dev/flutter/foundation/ChangeNotifier/addListener.html) method to update the UI based on the animation's current value.

Here's an example of how you can create an `AnimationController` for a simple fade-in animation:
```dart
import 'package:flutter/material.dart';

// The entry point for the Flutter app
void main() {
  // Run the app by passing the MyApp widget to runApp
  runApp(MyApp());
}

// MyApp is a stateless widget that returns MaterialApp
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // MaterialApp is the root of your application
    return MaterialApp(
      // MyHomePage is set as the home page of the app
      home: MyHomePage(),
    );
  }
}

// MyHomePage is a StatefulWidget
class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

// _MyHomePageState is the State class for MyHomePage class
class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  // Declare an AnimationController
  late AnimationController _controller;

  // Declare an Animation
  late Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    // Initialize the AnimationController with a duration of 2 seconds
    // and the 'vsync' parameter set to 'this' for performance reasons
    _controller = AnimationController(
      duration: Duration(seconds: 2),
      vsync: this,
    );

    // Create an animation that goes from 0.0 to 300.0
    _animation = Tween(begin: 0.0, end: 300.0).animate(_controller);

    // Add a listener to the animation to update the UI when the animation value changes
    _controller.addListener(() {
      setState(() {});
    });

    // Start the animation
    _controller.forward();
  }

  @override
  void dispose() {
    // Dispose the AnimationController when the widget is removed from the widget tree
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // Scaffold widget provides a default app bar, title, and body
    return Scaffold(
      appBar: AppBar(
        title: Text('Animation Examples'),
      ),
      // Center widget centers its child widget
      body: Center(
        // Container widget is a box model that can have width, height, and color
        child: Container(
          // Set the width and height of the container to the current value of the animation
          width: _animation.value,
          height: _animation.value,
          color: Colors.blue, // Set the color of the container to blue
        ),
      ),
    );
  }
}
```
In this example, we're using an `AnimationController` to animate the size of a [Container](https://api.flutter.dev/flutter/widgets/Container-class.html) widget. The `AnimationController` is initialized in the [initState](https://api.flutter.dev/flutter/widgets/State/initState.html) method, and the animation's value is updated using a `Tween` and a [listener](https://api.flutter.dev/flutter/widgets/Listener-class.html). The [dispose](https://api.flutter.dev/flutter/widgets/State/dispose.html) method is used to clean up the animation controller when the widget is removed from the widget tree.

![Animation](https://blog.openreplay.com/images/advanced-animation-techniques-for-flutter--a-guide/images/image1.gif)

This GIF demonstrates a simple animation in Flutter using an `AnimationController`. The blue square smoothly transitions from a small size to a larger size over 2 seconds.
    
## Physics-Based Animations
Flutter provides a [Simulation](https://api.flutter.dev/flutter/physics/Simulation-class.html) class that allows you to create [Physics-based animations](https://docs.flutter.dev/cookbook/animation/physics-simulation), such as spring animations, by defining the animation's behavior based on physical properties like [mass](https://api.flutter.dev/flutter/physics/SpringDescription/mass.html), [stiffness](https://api.flutter.dev/flutter/physics/SpringDescription/stiffness.html), and [damping](https://api.flutter.dev/flutter/physics/SpringDescription/damping.html).

Let's explore a physics-based animation example in Flutter called spring animation. By leveraging the `SpringSimulation` class, we can simulate an oscillator, which allows us to achieve a realistic spring-like effect in our animations.

Here's how you can create a spring animation using `SpringSimulation.`
```dart
import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';

void main() {
  runApp(MaterialApp(
    home: PhysicsSpringAnimationExample(),
  ));
}

class PhysicsSpringAnimationExample extends StatefulWidget {
  @override
  _PhysicsSpringAnimationExampleState createState() =>
      _PhysicsSpringAnimationExampleState();
}

class _PhysicsSpringAnimationExampleState
    extends State<PhysicsSpringAnimationExample>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;

  @override
  void initState() {
    super.initState();

    // Initialize the AnimationController
    _controller = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 500), // Animation duration
    );

    // Define the properties of the spring animation
    final SpringDescription _spring = SpringDescription(
      mass: 1, // Mass of the object
      stiffness: 100, // Stiffness of the spring
      damping: 10, // Damping of the spring
    );

    // Create a SpringSimulation for the spring animation
    final SpringSimulation _springSimulation =
        SpringSimulation(_spring, 0.0, 1.0, 0.5); // Starting position, end position, and velocity

    // Drive the animation using the SpringSimulation
    _animation = _controller.drive(
      Tween<double>(
        begin: _springSimulation.x(0), // Starting position
        end: _springSimulation.x(1), // End position
      ),
    );

    // Start the animation
    _controller.animateWith(_springSimulation);
  }

  @override
  void dispose() {
    // Dispose the AnimationController when done
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Spring Animation Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // AnimatedBuilder to rebuild the widget when the animation updates
            AnimatedBuilder(
              animation: _controller,
              builder: (context, child) {
                // Transform the widget using the scale value from the animation
                return Transform.scale(
                  scale: _animation.value,
                  child: Container(
                    width: 100, // Adjust size of animation
                    height: 100, // Adjust size of animation
                    color: Colors.blue,
                  ),
                );
              },
            ),
            SizedBox(height: 20),
            // Button to restart the animation
            ElevatedButton(
              onPressed: () {
                _controller.reset(); // Reset the animation
                _controller.forward(); // Start the animation
              },
              child: Text('Start Animation'),
            ),
          ],
        ),
      ),
    );
  }
}
```
This code sets up a Flutter app with a spring animation effect. When you run the app, a blue square will appear, animating as if it were attached to a spring. Pressing the 'Start Animation' button triggers the animation, causing the square to stretch and compress accordingly. The animation is controlled by an `AnimationController` and driven by a `SpringSimulation`, which defines the physics of the spring animation.
    
![SpringAnimation](https://blog.openreplay.com/images/advanced-animation-techniques-for-flutter--a-guide/images/image2.gif)

    
This GIF demonstrates a Flutter app with a spring animation effect. The animation shows a blue square that behaves as if it were attached to a spring, stretching and compressing based on the physics of an oscillator. Pressing the 'Start Animation' button triggers the animation, showcasing Flutter's capabilities.


<CTA_Middle_Cloud />



## Hero Animation
The [Hero](https://api.flutter.dev/flutter/widgets/Hero-class.html) widget in Flutter is used for shared element transitions, where an element (e.g., an image, or text) smoothly transitions from one screen to another. The `Hero` widget animates the shared element's size, position, and opacity to create a seamless transition effect.

### Implementation Example For Smooth Image Transitions
Let's consider a simple example of a `Hero` animation using two screens: `FirstScreen` and `SecondScreen`. In `FirstScreen`, we have an image wrapped in a `Hero` widget. When tapped, the image navigates to `SecondScreen`, where the same image is displayed with a smooth animation effect.
```dart
import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: FirstScreen(),
  ));
}

// First screen with a Hero animation
class FirstScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Screen'),
      ),
      body: GestureDetector(
        onTap: () {
          // Navigate to the second screen when the image is tapped
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => SecondScreen(),
            ),
          );
        },
        child: Hero(
          // Tag for the Hero animation, should be unique across screens
          tag: 'imageHero',
          // Image to be displayed in the Hero animation
          child: Image.network(
            "https://cdn.britannica.com/98/235798-050-3C3BA15D/Hamburger-and-french-fries-paper-box.jpg",
            // Make the image fill the width of the screen
            width: MediaQuery.of(context).size.width,
            // Set a fixed height for the image
            height: 200,
            // Cover the entire image with no distortion
            fit: BoxFit.cover,
          ),
        ),
      ),
    );
  }
}

// Second screen with a Hero animation
class SecondScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Screen'),
      ),
      body: GestureDetector(
        onTap: () {
          // Pop the current screen off the navigation stack when tapped
          Navigator.pop(context);
        },
        child: Hero(
          // Tag for the Hero animation, should be the same as in the first screen
          tag: 'imageHero',
          // Image to be displayed in the Hero animation
          child: Image.network(
            "https://www.aheadofthyme.com/wp-content/uploads/2021/11/veggie-tray-2.jpg",
            // Make the image fill the width of the screen
            width: MediaQuery.of(context).size.width,
            // Set a fixed height for the image
            height: 200,
            // Cover the entire image with no distortion
            fit: BoxFit.cover,
          ),
        ),
      ),
    );
  }
}
```
This code demonstrates how to use the `Hero` widget in Flutter to create a shared element transition between two screens. On the first screen, an image is displayed with a `Hero` widget. When the image is tapped, the app navigates to the second screen where the same image is displayed with a `Hero` `widget`. The `tag` property of the `Hero` widget is used to identify the same image across screens and animate its transition.

![Hero](https://blog.openreplay.com/images/advanced-animation-techniques-for-flutter--a-guide/images/image3.gif)


This GIF demonstrates a  `Hero` widget in action with this Flutter app. The animation smoothly transitions an image from the first screen to the second, creating a visually appealing effect. The `imageHero` tag ensures the images match up perfectly for a seamless transition.



## Implicit Animations
[Implicit animations](https://docs.flutter.dev/codelabs/implicit-animations) in Flutter are animations that are automatically applied to widgets when their properties change. These animations are triggered by changes in the widget's properties, such as size, position, or color, and do not require explicit animation controllers or [builders](https://api.flutter.dev/flutter/widgets/Builder-class.html).


The [AnimatedContainer](https://api.flutter.dev/flutter/widgets/AnimatedContainer-class.html) widget in Flutter is an example of an implicit animation. When the properties of the `AnimatedContainer` (e.g., width, height, color) change, Flutter automatically animates the transition between the old and new values, making smooth animation without the need for explicit code.
    
Implicit Animation Example
```dart
import 'package:flutter/material.dart';
import 'dart:math';

void main() {
  runApp(MaterialApp(
    home: ImplicitAnimationExample(),
  ));
}

class ImplicitAnimationExample extends StatefulWidget {
  @override
  _ImplicitAnimationExampleState createState() =>
      _ImplicitAnimationExampleState();
}

class _ImplicitAnimationExampleState extends State<ImplicitAnimationExample> {
  // Initial values for width, height, and color
  double _width = 100.0;
  double _height = 100.0;
  Color _color = Colors.blue;

  // Method to change the properties of the container
  void _changeProperties() {
    setState(() {
      final random = Random();
      _width = random.nextInt(300).toDouble(); // Random width
      _height = random.nextInt(300).toDouble(); // Random height
      _color = Color.fromARGB(
        255,
        random.nextInt(256), // Random red value
        random.nextInt(256), // Random green value
        random.nextInt(256), // Random blue value
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Implicit Animation Example'),
      ),
      body: Center(
        child: GestureDetector(
          onTap: _changeProperties, // Call _changeProperties on tap
          child: AnimatedContainer(
            duration: Duration(seconds: 1), // Animation duration
            curve: Curves.fastOutSlowIn, // Easing curve for the animation
            width: _width, // Animated width
            height: _height, // Animated height
            color: _color, // Animated color
            child: Center(
              child: Text(
                'Tap to change',
                style: TextStyle(color: Colors.white),
              ),
            ),
          ),
        ),
      ),
    );
  }
}
```
This code creates a simple Flutter app with an `AnimatedContainer` widget that animates changes to its width, height, and color properties. Tapping on the container triggers the animation, randomly changing its size and color. The animation duration is set to 1 second, and the easing curve used is `Curves.fastOutSlowIn`
    
![Implicit](https://blog.openreplay.com/images/advanced-animation-techniques-for-flutter--a-guide/images/image4.gif)

Flutter app demonstrating implicit animation with `AnimatedContainer`. The container changes size and color automatically, showcasing Flutter's smooth animation capabilities.

    
## Animated Vector Graphics
[Animated vector graphics (AVG)](https://pub.dev/packages/animated_svg) are graphics that use vector shapes and paths to create animations. In Flutter, AVG can be implemented using libraries like Rive and Lottie, which allow you to import vector graphics animations created in design tools like Adobe After Effects and Adobe Illustrator.
    
### Rive 
[Rive](https://pub.dev/packages/rive) is a powerful design and animation tool that allows you to create stunning animations and vector graphics for use in your Flutter applications. With Rive, you can easily design complex animations and export them to various formats for integration into your projects.

Here's a basic example of how you can integrate a Rive animation into your Flutter app:
```dart
import 'package:flutter/material.dart';
import 'package:rive/rive.dart'; // Import Rive package

void main() {
  runApp(MaterialApp(
    home: RiveAnimationExample(),
  ));
}

class RiveAnimationExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Rive Animation Example'),
      ),
      body: Stack(
        children: [
          // Display a Rive animation from an asset file
          RiveAnimation.asset(
            "assets/shapes.riv", // Path to the Rive animation asset
            fit: BoxFit.cover, // Fit the animation to the available space
          ),
        ],
      ),
    );
  }
}
```
    
This code sets up a Flutter app with a Rive animation effect. When you run the app, you'll see the Rive animation on the screen. The [RiveAnimation.asset](https://help.rive.app/runtimes/overview/flutter) `widget` is used to load and display the Rive animation from a file
    
To incorporate animated vector graphics in your Flutter animations using Rive, follow these steps:
1.  Create the animation using the [Rive](https://rive.app) website and download it in the appropriate format.
1.  Import the Rive [package](https://pub.dev/packages/rive) into your Flutter project.
1. Utilize the `RiveAnimation.asset` widget, providing the path to your Rive file.

![Untitleddesign-ezgif.com-video-to-gif-converter](https://blog.openreplay.com/images/advanced-animation-techniques-for-flutter--a-guide/images/image5.gif)


This code sets up a Flutter app that displays a Rive animation consisting of bouncing shapes (circle, triangle, and hexagon) on the screen. `The RiveAnimation.asset` widget is used to load and display the Rive animation from the `assets/shapes.riv` file. The animation is overlaid on the screen using a [Stack](https://api.flutter.dev/flutter/widgets/Stack-class.html) widget, allowing multiple widgets to be displayed on top of each other
    

### Lottie Animations
[Lottie](https://pub.dev/packages/lottie) is an open-source animation file format that's lightweight and easy to use. It's designed to render vector animations and graphics in a way that's scalable and resolution-independent. Lottie animations are created using [Adobe After Effects](https://www.adobe.com/products/aftereffects.html) and exported using the [Bodymovin](https://aescripts.com/bodymovin/#) plugin. These animations can be easily integrated into mobile, web, and desktop applications.
    
In Flutter, the Lottie library allows developers to add Lottie animations to their apps. This library provides widgets for loading and displaying Lottie animations, making it simple to include complex animations in Flutter apps without sacrificing performance. Lottie animations can enhance the user experience by adding visually appealing and engaging graphics to your app.
    
Here’s an example of how to create Lottie animations in Flutter:
```dart
import 'package:flutter/material.dart'; // Import the Flutter material library
import 'package:lottie/lottie.dart'; // Import the Lottie library for animations

void main() {
  runApp(MaterialApp(
    home: LottieAnimationExample(), // Set the home screen to LottieAnimationExample
  ));
}

class LottieAnimationExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Lottie Animation Example'), // Set the title of the app bar
      ),
      body: Center(
        // Center aligns its child widget
        child: Lottie.asset(
          'assets/lottie.json', // Path to the Lottie animation asset
          width: 200, // Set the width of the animation
          height: 200, // Set the height of the animation
          fit: BoxFit.cover, // Fit the animation to cover the entire space
        ),
      ),
    );
  }
}
```
This Flutter code sets up an app that displays a Lottie animation. The `Lottie.asset` widget loads and displays the animation from a JSON file, and the app bar (`AppBar`) provides a title for the app. When the app is run, the animation will be centered on the screen and cover the entire space available to it.
    
![lottie](https://blog.openreplay.com/images/advanced-animation-techniques-for-flutter--a-guide/images/image6.gif)

Bring your app to life with Lottie! This powerful library allows you to easily add high-quality animations to your Flutter app. Simply import your animation in Lottie format (JSON), use the Lottie package, and showcase your animations with ease.
    
## Conclusion
In conclusion, Flutter's comprehensive animation framework offers developers a wide array of tools and APIs to create captivating user experiences. By mastering these techniques, developers can seamlessly integrate animations into their apps, enhancing user engagement and overall app quality. From implicit animations to physics-based simulations and shared element transitions, Flutter provides the flexibility and scalability needed to bring apps to life. 

As Flutter continues to evolve, developers are encouraged to explore these advanced animation techniques further, pushing the boundaries of what's possible in mobile app development. By leveraging Flutter's animation capabilities, developers can deliver apps that not only meet but exceed user expectations, setting new standards for user interface design and interaction