ゴブサタしてます。
スマホアプリをメインに開発しているロッキーカナイです。
FlutterでRiveをやってみようと思って色々触っている時にタップ検知について疑問があり調べていたのですが、日本語解説がなかったので、記事にしてみました。
目次
Rive

ベクター2Dアニメーションを作成できるWebツールです。
Riveを用いるとFlutterで強力なアニメーション表現が可能となります。導入もとても簡単なので、アプリに動きを入れたい場合にとてもおすすめです。
導入方法
今回は主にアニメーションファイルにボタン、選択エリアがある場合の制御について説明したいと思いますので、基本的なRiveアニメーションの作成やflutter導入に関しては、先人たちが残してくれている素晴らしい記事を参考にしてみてください。
Riveでのアニメーション作成からflutter読み込み
Rive(旧 Flare) でつくる Flutter アニメーション
【Flutter】Flutter × RIVE でアニメーション対応
スプラッシュスクリーンアニメーション
Rive作成画面

素材をインポートしてって、時間時軸上にアニメーションを決めていく感じになります。
やりたい事
Riveアニメーション内にボタンを配置したい場合どうすればいいのか?
例としては以下の通りです。(ちょっと長め)
このようにRiveアニメーションの最後にボタンが出てくるようなパターンの場合です。
チュートリアルなどを見てみるとボタン自体は独立しており、GestureDetectorやボタン系のwidgetの子として扱う方法がありました。
Building a Water Tracking App with Flare & Flutter
1 2 3 4 5 6 7 8 9 10 11 12 13 |
GestureDetector( child: SizedBox( width: 100, height: 100, child: FlareActor( "assets/check_button.flr", animation: "check_on", ), ), onTap: () { // タップ検知 }, ), |
ですが、アニメーション内にボタンを配置したい場合もありますよね。
詳しく調べてみると、2通りの方法がありました。
対応方法1
アニメーションの親にGestureDetectorなどジェスチャー検知を与えて、タップ位置がヒットしたか判断する。
Reducing boilerplate code in Flutter using Flare
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
GestureDetector( onTapUp: (tapInfo) { var localTouchPosition = (context.findRenderObject() as RenderBox).globalToLocal(tapInfo.globalPosition); print("tap offset x: ${localTouchPosition.dx} y: ${localTouchPosition.dy}"); if (/* 選択エリア条件 */) { // 選択した場合の処理 } }, child: FlareActor( "assets/4s4ki.flr", animation: "play", fit: BoxFit.cover, ), ), |
なんか思ってたのと違う!
Cocos2dxのCocos Studioみたいな感じを勝手に想像しており、タップしたらコールバック関数が呼ばれるとか思ってましたが、違うようです。なので、ちょっとここは手間ですね。
対応方法2
smart_flareライブラリを使用しタップを検知する。
SmartFlare – Interactive FlareActors in Flutter – An Experiment
smart_flareライブラリを使用すると若干楽にできそうです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
SmartFlareActor( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, filename: "assets/4s4ki.flr", startingAnimation: "play", activeAreas: [ ActiveArea( area: Rect.fromLTWH( 0, 105, MediaQuery.of(context).size.width - 100, 100, ), debugArea: true, animationsToCycle: ['play'], onAreaTapped: () { print('Button tapped!'); }, ), ], ), |
ActiveAreaつまり、タップ検知したいエリアを設定し、タップされたらonAreaTappedのコールバック関数が実行されます。
しかもパラメータにdebugAreaというフラグがあり、trueにするとエリアがデバッグ表示されますので便利です。
以下は、debugArea = trueの場合です。

注意点
2通りの方法を紹介しましたが、画面全体に表示する場合、注意点があります。
Riveアニメーションが画面全体に表示する場合に余白が生まれてしまう
今回サンプルで作ったRiveアニメーションが画面全体に表示されるもを想定しました。smart_flareライブラリを使用した場合、SmartFlareActorクラスでアニメーションの指定等を行うのですが、BoxFitの操作が出来ない為、初期値のcontainになってしまいます。よってサイズを指定したとしても、サイズが異なる画面サイズの場合は余白が生まれてしまいます。
iPhoneXサイズ(1125*2436)にてアニメーション作成
iPhoneX

Android(アスペクト不一致)

とりあえず、BoxFit調整が必要なアニメーションの場合は、面倒でも純正ライブラリでタップ検知をするのがよいかと思います。
最後に
今回はFlutterでRiveアニメーションを利用した際のタップ検知についてまとめてみました。
最近スプラッシュでもアニメーションさせているアプリが多く、動きがあるといいですよね。Riveを使って簡単に実装できるので是非やってみてはいかがでしょうか!
使用した素材達
アサキ役 FTA/春
ブレッド君 イラストレイン
吹き出しフキダシデザイン
