preface

We have covered many chapters on animation before. For details, check out the chapters related to The Animation of Flutter Introduction and The Real World, or download the animation source code to see some examples. The previous animations have only one animation effect. What if we want to implement a set of animation effects on a component, such as the following?

This is when combined motion effects are needed, and Flutter provides Staggered Animation to achieve this. For multiple Anmation objects, you can share a single AnimationController and perform the animation at different times. This is a bit like a GIF image, where so many frames are played to achieve continuous animation.

Staggered animation mechanism

The implementation of staggered animation is based on the following points:

  • All animation objects use the same oneAnimationControllerDrive;
  • Regardless of how long the actual animation lasts, the animation controllercontrollerMust be between 0 and 1;
  • Each animation object has an interval between 0 and 1 (Interval);
  • In the interval,TweenObject transitions from a start value to an end value.
  • byAnimationControllerUnified management of the Tween generationAnimationObject.

It sounds a bit abstract, but it is much clearer to express it in a single diagram. Suppose we have four animation objects that control Opacity, Width, Height and Color of the component respectively, and the interleaving animation process is as follows:

The 0-1 of controller is a normalized animation control, which actually corresponds to the normalized animation duration. Meanwhile, the active effect of Opacity occupies a range of 0-0.25; Width occupies the range 0.25-0.5; Height occupies the range of 0.5-0.75; Finally, Color occupies a range of 0.75 to 1.0. The interval corresponds to the time interval of the animation, but the Tween animation object within each interval is in the range of 0 to 1 to control from the start value to the end value. The AnimationController concatenates multiple Animation objects in sequence (or superposition) to form a composite Animation.

Code implementation

If the instructions above seem a little confusing, let’s take a sample code to make it easy to understand. In the following code we define a common _controller and animate four objects _opaticy, _width, _height and _color. The key implementation is to use the animate method of the Tween object and specify a CurvedAnimation object as its parent parameter. The CurvedAnimation actually uses Interval to slice the _controller Animation time, allowing multiple Animation objects to be combined.

import 'package:flutter/material.dart';

class StaggeredAnimationDemo extends StatefulWidget {
  StaggeredAnimationDemo({Key? key}) : super(key: key);

  @override
  _StaggeredAnimationDemoState createState() => _StaggeredAnimationDemoState();
}

class _StaggeredAnimationDemoState extends State<StaggeredAnimationDemo>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _opacity;
  late Animation<double> _width;
  late Animation<double> _height;
  lateAnimation<Color? > _color;@override
  void initState() {
    _controller =
        AnimationController(duration: Duration(seconds: 2), vsync: this)
          ..addListener(() {
            setState(() {});
          });
    _opacity = Tween<double>(begin: 0.5, end: 1.0).animate(
      CurvedAnimation(
        parent: _controller,
        curve: Interval(
          0.0.0.25,
          curve: Curves.easeIn,
        ),
      ),
    );
    _width = Tween<double>(begin: 0.0, end: 2.0).animate(
      CurvedAnimation(
        parent: _controller,
        curve: Interval(
          0.25.0.5,
          curve: Curves.easeIn,
        ),
      ),
    );
    _height = Tween<double>(begin: 0.0, end: 2.0).animate(
      CurvedAnimation(
        parent: _controller,
        curve: Interval(
          0.5.0.75,
          curve: Curves.easeIn,
        ),
      ),
    );
    _color = ColorTween(begin: Colors.green, end: Colors.blue).animate(
      CurvedAnimation(
        parent: _controller,
        curve: Interval(
          0.75.1.0,
          curve: Curves.easeIn,
        ),
      ),
    );
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Staggered animation'),
      ),
      body: Center(
        child: Opacity(
          opacity: _opacity.value,
          child: Container(
            width: 100 + 100 * _width.value,
            height: 100 + 100 * _height.value,
            color: _color.value,
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.play_arrow),
        onPressed: () {
          setState(() {
            if (_controller.isCompleted) {
              _controller.reverse();
            } else if(! _controller.isAnimating) { _controller.forward(); }}); },),); }}Copy the code

If we look at the animation, we can see that the animation process is actually a Mosaic of 4 animation effects, the display transparency changes, then the width changes, then the height changes, and finally the color changes.

The Interval is introduced

Let’s take a look at the key Interval class.

A curve that is 0.0 until [begin], then curved (according to [curve]) from 0.0 at [begin] to 1.0 at [end], then remains 1.0 past [end].

The Interval class inherits from Curve, except that the Curve stays at 0.0 until begin and 1.0 after end. After the AnimationController starts the animation, the Interval curve is already drawn, but only between begin and end. Here is an example of an Interval curve.

As can be seen from Interval’s source code, clamp method limits the value range to 0 when t <= begin and 1.0 when t >= end.

@override
double transformInternal(double t) {
  assert(begin >= 0.0);
  assert(begin <= 1.0);
  assert(end >= 0.0);
  assert(end <= 1.0);
  assert(end >= begin);
  t = ((t - begin) / (end - begin)).clamp(0.0.1.0);
  if (t == 0.0 || t == 1.0)
    return t;
  return curve.transform(t);
}
Copy the code

conclusion

This paper introduces the implementation mechanism and examples of interlacing animation, through interlacing animation gives us more space for dynamic effect combination, so that we can achieve the kind of multi-frame combination of animation effect similar to GIF pictures.

I am dao Code Farmer with the same name as my wechat official account. This is a column about the introduction and practice of Flutter, providing systematic learning articles about Flutter. See the corresponding source code here: The source code of Flutter Introduction and Practical column. If you have any questions, please add me to the wechat account: island-coder.

👍🏻 : feel the harvest please point a praise to encourage!

🌟 : Collect articles, easy to look back!

💬 : Comment exchange, mutual progress!