【Flutter×Rive】FlutterでFlareアニメーションを連続再生する方法


追記 2021.3.6

Rive2 が公開されたのに伴い、旧Rive のURLが変わりました。
本記事は、旧Rive について記述してものになりますので、ご了承ください。

概要

Riveでは複数のアニメーションをもつFlareアニメーションを作ることができます。これを使えば、ルーレット的なものも簡単に実装できるのではと考え、実際にやってみました。

ざっくりいうと・・・

この記事の検証に使ったリソース

Riveの作品。Forkして改変することも含め、自由に使っていただくことができますので、必要に合わせてご利用ください。

Flutterのソースコード。こちらも改変することも含め、自由に使っていただくことができますので、必要に合わせてご利用ください。

環境

バージョン

  • Flutter 1.20.1

プロジェクト設定

  • この記事では、FlutterプロジェクトのUse androidx.* artifactsONに設定して検証しました。

本編

1) Riveで複数のアニメーションが定義された2Dアニメーションを作成する

私は shuffleという最初のアニメーションと、
result_1result_6という後続のアニメーションを作成しました。

shuffle result_6

作り方の詳細は省略しますが、ざっくりいうと・・・

いくつか、TIPS。

  • 個々のアニメーションは独立しています。それぞれで00:00:00からのアニメーションを作成します。
  • といいつつも・・・、Flutterでアニメーションを連続再生すると、パーツのプロパティ値は引き継がれます。
  • つまり、アニメーション2で表示するパーツを、先行のアニメーションでOpacity=0にしていたら、連続再生時にはそのパーツはアニメーション2の上でもOpacity=0となります。なのでそのような場合は、アニメーション2の00:00:00でOpacity=1をセットしましょう。
  • アニメーションは右クリックメニューからDuplicateを選択するとコピーできます。
  • 回転は、0° -> 15° -> 350° -> 15° -> 350° という形で変化をつけました。

あと、複数のアニメーションの話ではないですが・・・Drop ShaddowBlurなどのエフェクトを多用すると、Android上でのアニメーションの再生がカクカクしがちです。(iPhoneではそんなことはないのに)。なのでエフェクトは必要最小限にとどめるようにしたほうがよさそうです。(あたりまえか・・・)。

2) 初期画面でスプラッシュアニメーションを連続再生できるように改修する

改修のベースは、「【はじめてのRive】Flutterに2Dアニメーションスプラッシュスクリーンを導入する手順」で作成されたソースとします。

2-a) アニメーションを制御するコントローラークラスを作成する

FlareControlsを継承するコントローラークラス_AppSplashControllerを作成しましょう。

ここでは、スプラッシュアニメーションに対するコントローラークラスなので、このアプリのほかの個所で再利用することもないでしょうから、同じソースファイル内にプライベートクラスとして作ることにします。

app_splash_page.dartの下部に、以下のコードを追加しましょう。

app_splash_page.dart
class _AppSplashController extends FlareControls {

  final int number;
  final FlareCompletedCallback callback;
  _AppSplashController({
    @required this.number,
    this.callback
  });

  @override
  void initialize(FlutterActorArtboard artboard) {
    super.initialize(artboard);
    play('shuffle');
  }

  @override
  void onCompleted(String name) {
    if (name == 'shuffle') {
      play('result_$number');
      return;
    }
    callback?.call(name);
  }
}
  • initializeメソッドで、最初に再生するアニメーション名をコード: play('shuffle') で指定しています。
  • onCompletedメソッドは各アニメーションの再生が終わるごとに呼び出されるので、shuffleアニメーションが終わったらresult_アニメーションを、コンストラクタで与えられた数値に基づいて再生するようにしています。
  • callbackは、すべてのアニメーションが完了したタイミングで処理を実行させるために必要です。

2-b) アニメーションを制御するコントローラークラスを利用する

では、作成したコントローラークラス_AppSplashControllerを組み込みましょう。
組み込むためには、FlareActorのcontrollerプロパティに_AppSplashControllerを指定します。

app_splash_page.dart
class _AppSplashPageState extends State<AppSplashPage>{

  @override
  Widget build(BuildContext context) {
    var resultNumber = Random().nextInt(6) + 1;
    ...(中略)...
        child: FlareActor(
          'assets/app_splash_roulette.flr',
          alignment: Alignment.center,
          fit: BoxFit.contain,
          controller: _AppSplashController(
            number: resultNumber,
            callback: (name) {
              Future.delayed(Duration(milliseconds: 500)).then((value) {
                Navigator.of(context).pushReplacementNamed("/home");
              });
            },
          ),
        )
    ...(中略)...
  }
}

  • controllerプロパティに _AppSplashControllerを指定。
  • _AppSplashControllerにランダムに求めた数値を渡すことで公正(※1)なルーレットを実現。
  • _AppSplashControllerにアニメーション完了後のコールバックで、ホーム画面への遷移処理を実装。ルーレットの結果を味わえる(※2)500msの遅延を定義。

※1 厳密さに対するツッコミは無しで。。。
※2 個人の感想です。

動作確認

では早速、デバイスで動作させてみましょう。
以下、リリースビルドして動作させた結果です。

flutter run --release

6が出ました。今日は良いことありそうです。

じゃなくて・・・。

アニメーションの連続再生がスムーズにできましたね!

最後に

コントローラークラスを使えば他にも、時間経過に応じて処理を組み込んだり(advanceメソッド)、Nodeを使ってパーツを動かしたりなど、いろんなことが出来るようです。そのあたりはRiveの公式のドキュメント、チュートリアルや公開作品から学習することができます。

私ももっと学習を進めて、面白いことができるようになったら、また記事で公開したいなーと思うところ。。。

この記事が1人でも多くの方の助けになれば幸いです。