複数のアニメーションを１つにまとめる

#概要

例として、次のようなアニメーションを作ります。

![sequanceAnimation.gif](https://qiita-image-store.s3.amazonaws.com/0/266232/01d4b391-7c25-dfd8-3a43-86129042c7cd.gif)



複数のアニメーションを1つにまとめる方法はいくつかあるようですが、
今回は、[「flutter_sequence_animation」](https://github.com/Norbert515/flutter_sequence_animation)というライブラリを紹介したいと思います。

ライブラリを使用しない実装方法については、下記が参考になります
https://flutter.io/animations/staggered-animations/


#実装
##インストール
```pubspec.yaml
dependencies:
  flutter_sequence_animation: "^2.0.0"
```

```
$ flutter packages get
```
##アニメーションを作る

ライブラリが提供する`SequenceAnimationBuilder`を使ってアニメーションを作ります。
この例では、

+ 0.0〜4.0秒 
    + 色 red -> amber
+ 0.0〜2.0秒 
    + 横幅 50.0 -> 200.0
+ 2.0〜3.8秒 
    + 高さ 50.0 -> 200.0

の3つのアニメーションを一つにまとめています。
Flutterのアニメーションのコードとしては、驚きの読みやすさだと思います。


```dart
sequenceAnimation = SequenceAnimationBuilder()
        .addAnimatable(
            animatable: ColorTween(begin: Colors.red, end: Colors.amber),
            from: const Duration(seconds: 0),
            to: const Duration(seconds: 4),
            curve: Curves.easeInOut,
            tag: 'color'
        )
        .addAnimatable(
            animatable: Tween<double>(begin: 50.0, end: 200.0),
            from: const Duration(milliseconds: 0),
            to: const Duration(milliseconds: 2000),
            curve: Curves.easeInOut,
            tag: 'width'
        )
        .addAnimatable(
            animatable: Tween<double>(begin: 50.0, end: 200.0),
            from: const Duration(milliseconds: 2000),
            to: const Duration(milliseconds: 3800),
            curve: Curves.easeInOut,
            tag: 'height'
        )
        .animate(controller);
```

##レイアウトを作る

`AnimatedBuilder`を使ってレイアウトを作ります。
設定したtagを使って各値を参照します。

```dart
new AnimatedBuilder(
      animation: controller,
      builder: (context,child){
        return Center(
          child: Container(
            color: sequenceAnimation['color'].value,
            width: sequenceAnimation['width'].value,
            height: sequenceAnimation['height'].value,
          ),
        );
      },
    )
```

##コード全体

```animation_page.dart


import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_sequence_animation/flutter_sequence_animation.dart';

class AnimationPage extends StatefulWidget{
  @override
  State<StatefulWidget> createState() {
    return _AnimationPageState();
  }
}

class _AnimationPageState extends State<AnimationPage>
    with SingleTickerProviderStateMixin{

  AnimationController controller;
  SequenceAnimation sequenceAnimation;

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

    controller = AnimationController(vsync: this);

    sequenceAnimation = SequenceAnimationBuilder()
        .addAnimatable(
            animatable: ColorTween(begin: Colors.red, end: Colors.amber),
            from: const Duration(seconds: 0),
            to: const Duration(seconds: 4),
            curve: Curves.easeInOut,
            tag: 'color'
        )
        .addAnimatable(
            animatable: Tween<double>(begin: 50.0, end: 200.0),
            from: const Duration(milliseconds: 0),
            to: const Duration(milliseconds: 2000),
            curve: Curves.easeInOut,
            tag: 'width'
        )
        .addAnimatable(
            animatable: Tween<double>(begin: 50.0, end: 200.0),
            from: const Duration(milliseconds: 2000),
            to: const Duration(milliseconds: 3800),
            curve: Curves.easeInOut,
            tag: 'height'
        )
        .animate(controller);
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  Future<Null> _playAnimation() async {
    try {
      await controller.forward().orCancel;
      await controller.reverse().orCancel;
    } on TickerCanceled {
      // the animation got canceled, probably because we were disposed
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: GestureDetector(
        onTap: (){
          _playAnimation();
        },
        child: _buildBody(),
      ),
    );
  }

  Widget _buildBody(){
    return GestureDetector(
      onTap: (){
        _playAnimation();
      },
      child: AnimatedBuilder(
        animation: controller,
        builder: (context,child){
          return Center(
            child: Container(
              color: sequenceAnimation['color'].value,
              width: sequenceAnimation['width'].value,
              height: sequenceAnimation['height'].value,
            ),
          );
        },
      ),
    );
  }
}
```

#参考
使用したライブラリ
https://github.com/Norbert515/flutter_sequence_animation