Get in touch
or send us a question?
CONTACT

Flutter animation basics with implicit animations

In this series of posts, we’re going to introduce you to animations in Flutter, and show you how to build both simple and complex animations for your Flutter app.

This post is also available as a video, if you prefer.

In this first post, we’re going to focus on the most straightforward way to add animations to your app. You don’t have to be an expert on animations or animation terminology to add animations to your app. Along the way, we’ll introduce some widgets and terminology that will help you get started with animations right away and give you some background for the rest of the posts in the series.

Implicitly animated widgets

Flutter includes a series of widgets that are animated versions of existing widgets that you probably already used in your app, such as the AnimatedContainer version of the Container widget and the AnimatedPositioned version of the Positioned widget.

These widgets automatically animate changes to their properties. When you rebuild the widget with new property values, such as with a StatefulWidget’s setState, the widget handles driving the animation from the previous value to the new value.

Image for post

These widgets are called Implicitly Animated Widgets. They are typically the first thing you reach for when you need to add animations to your app. They provide a way to add animations without adding additional complexity.

The AnimatedContainer widget

Let’s look a little closer at how you can use one of these implicitly animated widgets to add some animation to your app.

In this app, there is a container and a button. When the button is pressed, setState is called, and the container is rebuilt with a new value for width. Notice that the container changes its width immediately, without any animation.

Image for post
@override
Widget build(BuildContext context) {
  return Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
      Container(
        width: _bigger ? 100 : 500,
        child: Image.asset('assets/star.png'),
      ),
      RaisedButton(
        onPressed: () => setState(() {
          _bigger = !_bigger;
        }),
        child: Icon(Icons.star),
      ),
    ],
  );
}

We can add some animation to this app by switching the Container widget for an AnimatedContainer widget and specifying an animation duration.

AnimatedContainer(
  width: _bigger ? 100 : 500,
  child: Image.asset('assets/star.png'),
  duration: Duration(seconds: 1),
),

Now, when the button is pressed, the container gradually animates from the previous width value to the new value.

Image for post
The star now animates between its states

The process of animating through the values between the old and new value is called interpolation. The AnimatedContainer handles interpolating its properties between the old and the new values whenever they change.

This applies to all of the AnimatedContainer’s properties, including, for example, the decoration. We can modify the gradient within a decoration and the AnimatedContainer handles interpolating between the old and new gradient:

AnimatedContainer(
  decoration: BoxDecoration(
    gradient: RadialGradient(
      colors: [Colors.purple, Colors.transparent],
      stops: [ _bigger ? 0.2 : 0.5, 1.0])
  ),
),
Image for post

The star now has an animated gradient

Controlling the animation with duration and curves

Implicitly animated widgets like AnimatedContainer have two properties that you can use to control the animation’s behavior. You can control how long it takes to interpolate to the new value by setting the duration property.

AnimatedContainer(
  width: _bigger ? 100 : 500,
  child: Image.asset('assets/star.png'),
  duration: Duration(seconds: 5),
),
Image for post

In this example, we made the animation take a much longer amount of time.

You can also control the way the widget interpolates from the old to the new value by using a Curve. Curves control the rate of change over time and can help your animations feel more realistic. In this example, we changed the curve from the default linear curve to a more exaggerated quintic curve:

AnimatedContainer(
  width: _bigger ? 100 : 500,
  child: Image.asset('assets/star.png'),
  duration: Duration(seconds: 1),
  curve: Curves.easeInOutQuint,
),
Image for post

There are many different built-in Curves available to give your animations a bit of character, and you can also define your own custom curves. Curves can even be discontinuous, like the SawTooth curve.

Here’s an example of a custom curve called SineCurve that uses the sine function to make a curve that bounces:

class SineCurve extends Curve {
  final double count;
 
  SineCurve({this.count = 1});
 
  @override
  double transformInternal(double t) {
    return sin(count * 2 * pi * t) * 0.5 + 0.5;
  }
}

Here, SineCurve makes the star bounce up and down:

Image for post

Now that is a happy star

To recap

Flutter provides implicitly animated widgets that are animated versions of common widgets. You can control the way these widgets animate using durations and curves.

AnimatedContainer is one notably powerful implicitly animated widget because it has many properties that affect its appearance, and all of them are automatically interpolated.

All of the other implicitly animated widgets are also powerful, easy-to-use options for adding animations without adding a lot of complexity.

Also, you don’t necessarily need to place these widgets into a StatefulWidget and use setState, you can use StreamBuilder and FutureBuilder to trigger animations like in this example.

Digging deeper into animations

Implicitly animated widgets are your first choice for adding animations, however, this isn’t all that Flutter’s animation system has to offer. In the rest of this series, we explore the lower layers of the Flutter animation system, and show you how you can build advanced animations by using the animation system directly.

For everything else, visit flutter.dev.

Articles in this series:

source: link