🐖

【Flutter】Lottie 1つのファイルから複数アニメーションを実装する

2024/07/15に公開

今回やること

複数の Lottie アニメーションを実装する際に、アニメーションごとに複数のファイルに分けるのではなく、
1 つのファイルに複数のアニメーションを集約し、実装時に個別アニメーションを抽出する。
つまりやりたいのは、6.0 秒のアニメーションの中で 4.0~6.0 の間をループするなど、部分的に切り出してアニメーションを実装することです。

実行例
個別アニメーションをインタラクティブに活用した例

Lottie の構成

実行例

このように 1 つのアニメーションに対し、部分的にそれぞれの個別アニメーションを作成します。

作成した個別アニメーション: Hover, Send, Done, Failed, Load

1 つのファイルを連続再生すると下のようになります。これを部分的に切り取って使用します。
実行例

専用のコントローラーを作成する

特定の部分をループさせたり、特定の部分のアニメーションのみを実行したいので、
専用のコントローラーを作ると便利です。AnimationController を継承します。

アニメーションの値は 0.0~1.0 で管理されるので、開始時間などは startSecond/duration(アニメーションの総時間) のように表します。

ループするアニメーション、フォワードするアニメーションを実装する。
個別のアニメーションの開始の秒数と終了の秒数を引数として取ります。

class LottieAnimationController extends AnimationController {
  LottieAnimationController({
    required super.vsync,
    super.duration,
  });

  
  void dispose() {
    super.dispose();
    _removeCurrentListener();
  }

  AnimationStatusListener? _listener;

  void pointLoop(
    double startSecond,
    double endSecond, {
    bool reverse = false,
  }) {

    _removeCurrentListener();

    if (reverse) {
      repeat(
          min: startSecond / duration!.inSeconds,
          max: endSecond / duration!.inSeconds,
          reverse: true,
          period: Duration(seconds: (endSecond - startSecond).toInt()));
    } else {
      value = startSecond / duration!.inSeconds;
      animateTo(endSecond / duration!.inSeconds);
      _listener = (status) {
        if (status == AnimationStatus.completed) {
          value = startSecond / duration!.inSeconds;
          animateTo(endSecond / duration!.inSeconds);
        }
      };
    }
    addStatusListener(_listener!);
  }

  Future<void> pointForward(double startSecond, double endSecond) async {

    _removeCurrentListener();

    value = startSecond / duration!.inSeconds;
    return animateTo(endSecond / duration!.inSeconds);
  }

  void _removeCurrentListener() {
    if (_listener != null) {
      removeStatusListener(_listener!);
      _listener = null;
    }
  }
}

実装側

開始秒数と終了秒数を指定して部分的にアニメーションさせる。

late LottieAnimationController _lottieController;


void initState() {
  super.initState();
  _lottieController = LottieAnimationController(
    duration!.inSeconds: 6.0,// 今回のアニメーションファイルの総時間
    vsync: this,
  );
}

/// hover アニメーションを実行する (0.0~1.0)
_lottieController.pointLoop(0.0, 1.0);

/// send アニメーションを実行する (1.0~1.6)
_lottieController.pointForward(1.0, 1.6);

/// build内
Lottie.asset(
  'assets/lottie/send.json',
    controller: _lottieController,
    onLoaded: (composition) {
      /// ロード時にアニメーションの総時間を取得する
      _lottieController.duration = composition.duration;
    },
),

実行例
hover

実行例
send

終わりに

今回は Lottie を Flutter で応用的に使用してみました。
個別のアニメーションごとにファイルを分けて管理するのも良いですが、
ファイルを 1 つにまとめると asset も煩雑にならずに管理が楽かなと思います。
また、Lottie は json ファイルですので、データを加工しやすいのも良いですね。

デモページ ↓   下記ページからデモとコードを確認できます。
https://shogoisaji.github.io/ui_playground_134/#/interactive_lottie

Discussion