追記 2021.3.6
Rive2 が公開されたのに伴い、旧Rive のURLが変わりました。
本記事は、旧Rive について記述してものになりますので、ご了承ください。
概要
Riveでは複数のアニメーションをもつFlareアニメーションを作ることができます。これを使えば、ルーレット的なものも簡単に実装できるのではと考え、実際にやってみました。
ざっくりいうと・・・
- Flutterアプリのスプラッシュアニメーションにルーレット機能を組み込みます。
- Flutterアプリのスプラッシュアニメーションを組み込む手順は、記事「【はじめてのRive】Flutterに2Dアニメーションスプラッシュスクリーンを導入する手順」をお読みください。
- アニメーションを制御するため、
FlareControls
クラスを継承したコントローラークラスを用意します。
この記事の検証に使ったリソース
Riveの作品。Forkして改変することも含め、自由に使っていただくことができますので、必要に合わせてご利用ください。
Flutterのソースコード。こちらも改変することも含め、自由に使っていただくことができますので、必要に合わせてご利用ください。
環境
バージョン
- Flutter 1.20.1
プロジェクト設定
- この記事では、Flutterプロジェクトの
Use androidx.* artifacts
はON
に設定して検証しました。
本編
1) Riveで複数のアニメーションが定義された2Dアニメーションを作成する
私は shuffle
という最初のアニメーションと、
result_1
~result_6
という後続のアニメーションを作成しました。
shuffle | result_6 |
作り方の詳細は省略しますが、ざっくりいうと・・・
- まずは「【はじめてのRive】Flutterに2Dアニメーションスプラッシュスクリーンを導入する手順」の手順を参考にしてください。
- Riveの
ANIMATE
ページの画面左下、ANIMATION
にある+
ボタンを押すと、アニメーションを追加できます。 - 本記事で作成したapp-splash-roulette - atsuteruも参考にしてください。
いくつか、TIPS。
- 個々のアニメーションは独立しています。それぞれで
00:00:00
からのアニメーションを作成します。 - といいつつも・・・、Flutterでアニメーションを連続再生すると、パーツのプロパティ値は引き継がれます。
- つまり、アニメーション2で表示するパーツを、先行のアニメーションでOpacity=0にしていたら、連続再生時にはそのパーツはアニメーション2の上でもOpacity=0となります。なのでそのような場合は、アニメーション2の
00:00:00
でOpacity=1をセットしましょう。 - アニメーションは右クリックメニューから
Duplicate
を選択するとコピーできます。 - 回転は、0° -> 15° -> 350° -> 15° -> 350° という形で変化をつけました。
あと、複数のアニメーションの話ではないですが・・・Drop Shaddow
やBlur
などのエフェクトを多用すると、Android上でのアニメーションの再生がカクカクしがちです。(iPhoneではそんなことはないのに)。なのでエフェクトは必要最小限にとどめるようにしたほうがよさそうです。(あたりまえか・・・)。
2) 初期画面でスプラッシュアニメーションを連続再生できるように改修する
改修のベースは、「【はじめてのRive】Flutterに2Dアニメーションスプラッシュスクリーンを導入する手順」で作成されたソースとします。
2-a) アニメーションを制御するコントローラークラスを作成する
FlareControls
を継承するコントローラークラス_AppSplashController
を作成しましょう。
ここでは、スプラッシュアニメーションに対するコントローラークラスなので、このアプリのほかの個所で再利用することもないでしょうから、同じソースファイル内にプライベートクラスとして作ることにします。
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
を指定します。
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人でも多くの方の助けになれば幸いです。