LoginSignup
2
1

はじめに

こんばんは。OREOです。
2024/6/12, 2024/6/13に開催された国内初のグローバルFlutterイベントFlutterNinjasに参加してきました!
素晴らしいセッションが盛りだくさんで非常に勉強になりました。
個人的に気になったセッションについて実際に実装してみようということで,何個か記事を書いてみようと思います!

RIVEとは

RIVE(リーヴ)は,インタラクティブでリアルタイムなアニメーションを作成するためのデザインツールです。UIやゲームのアニメーションを作成・デプロイでき,ベクターグラフィックスを使用するため高品質でスケーラブル。
FlutterやReact Nativeなどにも統合可能になっています。

例えばこんなアニメーションが作れるようです。
画面収録 2024-06-15 20.59.34.gif

参照元

Flutter上でアニメーションを動かしてみる

アニメーションの詳しい作成方法については本記事では割愛します。
この2種類のアニメーションをアプリに実装していきたいと思います。
アニメーションの違いとしては走行中はスクーターが跳ねているというところだけです。

走行中 停止中
画面収録 2024-06-16 0.35.11.gif 画面収録 2024-06-16 0.35.22.gif

|

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');
  }

RIVEの設定画面
スクリーンショット 2024-06-16 0.43.30.png

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!'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

実際の動作のようす

画面収録 2024-06-16 0.51.59.gif

さいごに

RIVEを使ってアニメーションの実装ができました!
アニメーション内部にListnerを持たせることもできる様なのでその辺の機能はまたの機会にトライしてみようと思います。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1