FlutterでTwitterアプリみたいなスプラッシュアニメーションを作ってみる

ツイッターによくある、ふわっと消えていくスプラッシュアニメーションをFlutterで実装したので共有します。

イメージは下記の記事にあるようなものです。

https://qiita.com/osamu1203/items/a7c78666b18eb499c94b


## 完成

完成はこんな感じです。

![Flutteranimation3.gif](https://qiita-image-store.s3.amazonaws.com/0/139360/342546a6-1165-41f3-db03-a1eba59063da.gif)


## 実装

### 1. 一回小さくしてそのあと元に戻す

一回小さくして大きくするアニメーションを実装していきます。
`AnimationController` と `Tween` クラスを使ってイメージをアニメーションさせていきます。


```dart

AnimationController _animationController;
Animation<double> _tweenAnimation;


_setAnimation() async {
    _animationController =
        AnimationController(duration: Duration(milliseconds: 500), vsync: this);
    _tweenAnimation =
        Tween(begin: 300.0, end: 250.0).animate(_animationController);
    _tweenAnimation.addListener(() => setState(() {}));
    await _animationController.forward();
    await _animationController.reverse();
  }

@override
  Widget build(BuildContext context) {
    var icIcon = new AssetImage('assets/ic_icon.png');
    return new Scaffold(
      body: Center(
          child: Image(
            image: icIcon,
            width: _tweenAnimation.value,
            height: _tweenAnimation.value,
          ),
      ),
    );
  }

```

`_setAnimation` メソッドを好きなところで呼ぶとそこからアニメーションし始めます。
自分は `initState()` で呼んでいます。これはスプラッシュ画面なので最初の一回しか呼ばれなくていいかと思いました。

`initState()` 以外で呼ぶとイメージのサイズが決定できなくなってしまってエラーになるのでいい感じに調整してください

```dart
child: Image(
    image: icIcon,
    width: _tweenAnimation.value,
    height: _tweenAnimation.value,
),

```
ここの部分でイメージの大きさをアニメーションにしたがって大きさを変えています。

### 2. フェードアウトさせる

フェードアウトは `AnimatedOpacity` というWidgetを使って実装します。
まずはイメージを表示しているウィジェットをラップします。

```dart

  bool _visible = true;

  @override
  Widget build(BuildContext context) {
    var icIcon = new AssetImage('assets/ic_icon.png');
    return new Scaffold(
      body: Center(
        child: AnimatedOpacity(
          opacity: _visible ? 1.0 : 0.0,
          duration: Duration(milliseconds: 500),
          child: Image(
            image: icIcon,
            width: _tweenAnimation.value,
            height: _tweenAnimation.value,
          ),
        ),
      ),
    );
  }

```

`Duration(milliseconds: 500)` は適宜変更してください。


### 3. １と2の処理を繋げていい感じにアニメーションさせる

それでは１と２のアニメーションを繋げていい感じにアニメーションさせます。


```dart

class _SplashState extends State<Splash>
    with SingleTickerProviderStateMixin<Splash> {
  bool isLogin = false;
  AnimationController _animationController;
  Animation<double> _tweenAnimation;

  bool _visible = true;

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

    _setAnimation();
    new Future.delayed(const Duration(seconds: 1))
        .then((value) => handleTimeout());
  }

  _setAnimation() async {
    _animationController =
        AnimationController(duration: Duration(milliseconds: 500), vsync: this);
    _tweenAnimation =
        Tween(begin: 300.0, end: 250.0).animate(_animationController);
    _tweenAnimation.addListener(() => setState(() {}));
    await _animationController.forward();
    await _animationController.reverse();
  }

  @override
  Widget build(BuildContext context) {
    var icIcon = new AssetImage('assets/ic_icon.png');
    return new Scaffold(
      body: Center(
        child: AnimatedOpacity(
          opacity: _visible ? 1.0 : 0.0,
          duration: Duration(milliseconds: 500),
          child: Image(
            image: icIcon,
            width: _tweenAnimation.value,
            height: _tweenAnimation.value,
          ),
        ),
      ),
    );
  }

  void handleTimeout() {
    setState(() {
      _visible = !_visible;
    });
    new Future.delayed(const Duration(milliseconds: 800)).then((value) {
      // ここでスプラッシュ後の画面を開かせる
    });
  }
}
```

全体のソースコードを載せました。

１、で作った小さくして大きくするアニメーションを実行します。
`milliseconds: 500` で設定しているので小さくして、大きくするまでちょうど1秒なので1秒遅延後にvisibleを変更して２、でつくったフェード処理を実装しています。


正直もっといい感じにやっていきたい、、、
誰かの力になれば。