はじめに
こんばんは。OREOです。
2024/6/12, 2024/6/13に開催された国内初のグローバルFlutterイベントFlutterNinjasに参加してきました!
素晴らしいセッションが盛りだくさんで非常に勉強になりました。
個人的に気になったセッションについて実際に実装してみようということで,何個か記事を書いてみようと思います!
RIVEとは
RIVE(リーヴ)は,インタラクティブでリアルタイムなアニメーションを作成するためのデザインツールです。UIやゲームのアニメーションを作成・デプロイでき,ベクターグラフィックスを使用するため高品質でスケーラブル。
FlutterやReact Nativeなどにも統合可能になっています。
Flutter上でアニメーションを動かしてみる
アニメーションの詳しい作成方法については本記事では割愛します。
この2種類のアニメーションをアプリに実装していきたいと思います。
アニメーションの違いとしては走行中はスクーターが跳ねているというところだけです。
走行中 | 停止中 |
---|---|
|
contollerの初期化
StateMachineControllerを設定を行います。今回はRIVEファイルのState Machine名は"State Machine 1"で設定しました。
void _onInit(Artboard artboard) {
final controller =
StateMachineController.fromArtboard(artboard, 'State Machine 1');
if (controller == null) {
return;
}
artboard.addController(controller);
_inputId = controller.getNumberInput('id');
}
RiveAnimation Widget
RIVEからエクスポートしたファイルを任意のディレクトに保存してください。今回はassets/animations
配下に保存しています。
今回はローカルファイルで実装を行ったので.asset
を使用しています。
SizedBox(
height: 450,
width: 500,
child: RiveAnimation.asset(
'assets/animations/mylogo.riv',
// idによってアニメーションを切り替える
animations: [_inputId?.value == 1 ? 'Running' : 'Idling'],
// 初期化時にコントローラーを取得
onInit: _onInit,
),
),
コード全容
アニメーションの状態をわかりやすくするためにアニメーション切り替えボタンとテキストを追加しています。
import 'package:flutter/material.dart';
import 'package:rive/rive.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
SMIInput<double>? _inputId;
@override
void initState() {
super.initState();
}
void _onInit(Artboard artboard) {
final controller =
StateMachineController.fromArtboard(artboard, 'State Machine 1');
if (controller == null) {
return;
}
artboard.addController(controller);
_inputId = controller.getNumberInput('id');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.black87,
title: const Center(
child: Text(
'Test App',
),
),
),
backgroundColor: const Color.fromARGB(255, 2, 39, 102),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
color: Colors.amber,
width: double.infinity,
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text('SCOOTER IS',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
)),
),
),
Container(
color: _inputId?.value == 1
? const Color.fromARGB(255, 56, 131, 58)
: const Color.fromARGB(255, 220, 73, 63),
width: double.infinity,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(_inputId?.value == 1 ? 'RUNNING' : 'STOP',
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
)),
),
),
SizedBox(
height: 450,
width: 500,
child: RiveAnimation.asset(
'assets/animations/mylogo.riv',
// idによってアニメーションを切り替える
animations: [_inputId?.value == 1 ? 'Running' : 'Idling'],
// 初期化時にコントローラーを取得
onInit: _onInit,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () {
setState(() {
_inputId?.value = 1;
});
},
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
const Color.fromARGB(255, 56, 131, 58)),
),
child: const Text('Start'),
),
ElevatedButton(
onPressed: () {
setState(() {
_inputId?.value = 2;
});
},
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
const Color.fromARGB(255, 220, 73, 63)),
),
child: const Text('Stop!'),
),
],
),
],
),
),
);
}
}
実際の動作のようす
さいごに
RIVEを使ってアニメーションの実装ができました!
アニメーション内部にListnerを持たせることもできる様なのでその辺の機能はまたの機会にトライしてみようと思います。