How to Create Animations in Flutter

Flutter animations are a way to make your app’s user interface more dynamic and engaging. They can help create smooth transitions, visual effects, and interactive elements that enhance the user experience. Here are some key points about Flutter animations:

  1. Types of Animations:

    • Implicit Animations: These are simple to implement and automatically handle the animation for you. Examples include AnimatedContainer, AnimatedOpacity, and AnimatedAlign.

    • Explicit Animations: These give you more control over the animation process. Examples include AnimationController, Tween, and AnimatedBuilder.

  2. Common Animation Widgets:

    • AnimatedContainer: Animates changes in its properties like size, colour, and alignment.

    • TweenAnimationBuilder: Allows you to define a tween (a way to interpolate between two values) and animate it.

    • AnimationController: Manages the animation’s duration and direction.

    • CurvedAnimation: Adds non-linear motion to animations, making them feel more natural.

  3. Animation Techniques:

    • Tweening: Interpolates between a start and end value over a specified duration.

    • Physics-based Animations: Simulate real-world physics, like spring or gravity animations.


Implicit Animations

Implicit animations in Flutter are built on several key components that make them easy to use and effective for creating smooth transitions.

Key Components for Implicit Animations:

  1. State Management:
  • Implicit animations rely on state changes. When a property of a widget changes, the animation automatically begins.

  • This is typically managed using setState in a StatefulWidget.

  1. Tweening:
  • Tweening refers to calculating intermediate values between the start and end points of an animation.

  • Flutter handles this internally for implicit animations, ensuring smooth transitions.

  1. Duration and Curve:
  • Duration: Specifies how long the animation should take to complete. This is set using the duration parameter.

  • Curve: Defines the rate of change of the animation over time. Common curves include Curves.easeIn, Curves.easeOut, and Curves.line

  1. Implicitly Animated Widgets:
  • Flutter provides several built-in widgets for implicit animations, such as:

  • AnimatedContainer: Animates changes in size, color, and other properties.

  • AnimatedOpacity: Animates changes in opacity.

  • AnimatedPadding: Animates changes in padding.

  • AnimatedPositioned: Animates changes in position within a Stack.

  • AnimatedDefaultTextStyle: Animates changes in text style.

Example of an Implicit Animation :

Here’s a simple example using AnimatedContainer to animate changes in size and colour:

class AnimatedContainerDemo extends StatefulWidget {
  @override
  _AnimatedContainerDemoState createState() => _AnimatedContainerDemoState();
}

class _AnimatedContainerDemoState extends State<AnimatedContainerDemo> {
  bool _isExpanded = false;

  void _toggleContainer() {
    setState(() {
      _isExpanded = !_isExpanded;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('AnimatedContainer Practice')),
      body: Center(
        child: AnimatedContainer(
          width: _isExpanded ? 200 : 100,
           height: _isExpanded ? 200 : 100,
          color: _isExpanded ? Colors.blue : Colors.red,
          alignment: Alignment.center,
          duration: Duration(seconds: 1),
          curve: Curves.easeInOut,
          child: Text('Press Me!', style: TextStyle(color: Colors.white)),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _toggleContainer,
        child: Icon(Icons.play_arrow),
      ),
    );
  }
}

In this example, tapping the button toggles the size and colour of the container, creating a smooth animation.

Implicit animations are a powerful tool for adding visual polish to your Flutter apps without the complexity of manually managing animation controllers.


Explicit Animations

Explicit animations in Flutter give you fine-grained control over the animation process, allowing you to define the animation’s behaviour, properties, and lifecycle. Unlike implicit animations, which handle the animation for you, explicit animations require you to manage the animation’s state and transitions manually.

Key Components of Explicit Animations:

  1. AnimationController:

    • Manages the duration, direction, and state of the animation.

    • Controls the animation’s lifecycle, including starting, stopping, and reversing.

  2. Tween:

    • Defines the range of values the animation will interpolate between.

    • Common types include Tween<double>, ColorTween, and SizeTween.

  3. CurvedAnimation:

    • Adds non-linear motion to the animation, making it more natural.

    • Uses predefined curves like Curves.easeIn, Curves.bounceOut, etc.

  4. AnimatedBuilder:

    • Rebuilds the widget tree whenever the animation value changes.

    • Provides a way to separate the animation logic from the widget tree.

Example of an Explicit Animation:

Here’s a simple example of an explicit animation that animates the size and colour of a container:

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('Explicit Animation Practice')),
        body: ExplicitAnimationDemo(),
      ),
    );
  }
}

class ExplicitAnimationDemo extends StatefulWidget {
  @override
  _ExplicitAnimationDemoState createState() => _ExplicitAnimationDemoState();
}

class _ExplicitAnimationDemoState extends State<ExplicitAnimationDemo> with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Animation<double> _sizeAnimation;
  Animation<Color> _colorAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 3),
      vsync: this,
    );

    _sizeAnimation = Tween<double>(begin: 50.0, end: 200.0).animate(_controller);
    _colorAnimation = ColorTween(begin: Colors.blue, end: Colors.red).animate(_controller);

    _controller.forward();
  }
 @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: AnimatedBuilder(
        animation: _controller,
        builder: (context, child) {
          return Container(
            width: _sizeAnimation.value,
            height: _sizeAnimation.value,
            color: _colorAnimation.value,
          );
        },
      ),
    );
  }
}

In this example:

  • AnimationController: Manages the animation’s duration and state.

  • Tween: Defines the start and end values for size and colour.

  • AnimatedBuilder: Rebuilds the container with the updated animation values.


Some common pitfalls to avoid in animation code:

When working with animations in Flutter, there are several common pitfalls to be aware of to ensure your animations are smooth and efficient. Here are some key ones to avoid:

  1. Overusing StatefulWidgets:
  • Pitfall: Using too many StatefulWidgets can lead to complex and hard-to-maintain code.

  • Solution: Use StatelessWidgets where possible and manage state efficiently with state management solutions like Provider, Riverpod, or GetX.

  1. Not Disposing Animation Controllers:
  • Solution: Always dispose of your animation controllers in the dispose method of your StatefulWidget.

  • Pitfall: Failing to dispose of animation controllers can lead to memory leaks.

  1. Unnecessary Rebuilds:
  • Pitfall: Rebuilding the entire widget tree unnecessarily can cause performance issues.

  • Solution: Use AnimatedBuilder or AnimatedWidget to optimise performance by only rebuilding the parts of the widget tree that need to be animated.

  1. Ignoring Perfomance Optimisation:
  • Pitfall: Not optimising animations can lead to janky and unresponsive UIs.

  • Solution: Use tools like the Flutter Inspector to track widget rebuilds and optimise performance. Avoid offscreen rendering and excessive use of saveLayer()

  1. Improper Use of Tween and Curves
  • Pitfall: Using linear animations for all transitions can make animations feel unnatural.

  • Solution: Use Tween and apply easing curves like Curves.easeInOut to create more natural animations**.**

  1. Animating Large Lists Inefficiently
  • Solution: Use ListView.builder or AnimatedList to efficiently handle large lists and their animations

  • Pitfall: Animating large lists directly can be resource-intensive.

  1. Overcomplicating Simple Animations
  • Pitfall: Using complex animation controllers for simple animations can make the code harder to manage.

  • Solution: Use implicit animation widgets like AnimatedContainer, AnimatedOpacity, and AnimatedPositioned for simpler animations.

  1. Not Testing Animations
  • Pitfall: Failing to test animations can lead to unexpected behaviour in production.

  • Solution: Write unit tests for your animation logic and use Flutter’s debugging tools to inspect and debug animations

Example:

Here’s an example of properly disposing of an animation controller:

class MyAnimation extends StatefulWidget {
  @override
  _MyAnimationState createState() => _MyAnimationState();
}

class _MyAnimationState extends State<MyAnimation> with SingleTickerProviderStateMixin {
  AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 3),
      vsync: this,
    );
    _controller.forward();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  } 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Animation Practice')),
      body: Center(
        child: Container(
          width: _controller.value * 300,
          height: _controller.value * 300,
          color: Colors.blue,
        ),
      ),
    );
  }
}

By avoiding these common pitfalls, you can create more efficient and maintainable animations in your Flutter applications.


In conclusion, mastering Flutter animations can significantly enhance your app's user experience by making the interface more dynamic and engaging. Understanding implicit and explicit animations, along with best practices, ensures your animations are visually appealing, efficient, and maintainable. Whether using simple implicit animations or complex explicit ones, these techniques can elevate the quality of your mobile applications.

10
Subscribe to my newsletter

Read articles from Fenisha Koladiya directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Fenisha Koladiya
Fenisha Koladiya