🪔

【Flutter】Riveを使ってインタラクティブなボタンアニメーションを作成し、UXを向上させたい!

2023/05/05に公開

モチベーション

  • ローディング中など待ち時間ができる場合のUXを向上させたい
  • ユーザーの視覚的手がかりを増やし、UXを向上させたい
  • アプリにリッチな印象を付与し、ユーザーのロイヤリティを高めたい

こんにちは、はがくんです。

FlutterのWidgetには標準装備されたいくつものアニメーションが設定されており、小さなアプリを作っている場合などは十分な場合がほとんどかと思います。

しかし、ユーザージャーニーの中で、操作手順の多さや待ち時間の発生によってユーザーが離脱してしまう可能性が考えられます。フローの整理などによって一部のUXを向上させることは可能ですが、サーバーのレスポンスにかかる時間などを制御しきれないこともあるでしょう。

そんなときに、フロント側でアニメーションを上手く利用し、ユーザーの体験を上手くコントロールすることができれば、アプリからのユーザーの離脱を防ぐことができるでしょう。

今回は、Riveを使ってアニメーションを作成する方法と、それをFlutter上で利用する方法について紹介します。

Rive Editorによるアニメーションの作成~保存の流れ

How to install Rive Editor

https://rive.app/editor

Riveアニメーションの作成はWeb版のエディタを利用することも可能ですが、Windows, Mac版のアプリケーションが提供されているので、そちらを利用していきましょう。

上記のリンクからインストールしてください。

Rive Editorでボタンを作成

Rive Editorでは、手持ちのSVGやPNGなどのアセットを読み込み、自由に配置することができます。

FigmaやPhotoshop, Illustratorなどのツールを使ってエクスポートしたものでも、Rive Editor上でRectangleなどの図形を配置することもできます。

今回は、簡単なボタンを作成して簡単なアニメーションを作成していきます。
まずは以下のようなボタンを作成してみました。

このボタンは、Rive Editorで作成したRectangleにSVGテキストとアイコンを配置しただけ。もちろん、これだけならFlutterのElevatedButtonなどを利用すればカンタンに実装できますが、ここにアニメーションを付けていきます。

Rive Editor で アニメーションを作成


Animateモードを選択すると、アニメーションを作成することができます。

画面下部を見ると、👆のようにタイムラインが表示されています。
このペインの左上に表示されるAnimations部分の+を押すことでアニメーションを追加していくことができます。

現在の状態を初期状態を意味するinitにリネームし、新たにsendアニメーションを作成しましょう。

画面右ペインに👆のようなインターフェースがあり、ここでキーフレームを設定するとアニメーションを設定することができます。Adobe Premire Proなどの動画編集ソフトに慣れている方だと分かりやすいかもしれません。

文章で説明すると分かりづらいところだと思いますが、Riveが公式のチュートリアルをYouTubeにアップロードしてくれています!

https://www.youtube.com/watch?v=zqaoTmtreFA

ドキュメントも作成してくれているため、そちらも参照してみると理解が深まるかもしれません。
https://help.rive.app/tutorial/bouncing-ball

initsendアニメーションを作成したら、Flutterでも動かせるようにコードを書いていきましょう。

riveアニメーションをエクスポート


アイコンから、Download → For runtime とすることで、.riv 形式のアニメーションファイルをダウンロードできます。

このファイルをFlutterのアセットとして読み込むことで、Riveアニメーションを利用していきましょう。

(Windowsのみ)Viual Studio installer から Clangをインストール

Windows用のビルドを行う場合clangコンパイラのインストールが必要になるため、Visual Studio installerからインストールしておきましょう。

https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild?view=msvc-170

Flutter で .rivファイルを読み込んでアニメーションを利用する

assetフォルダに.rivを設定する

プロジェクトのルートフォルダにassetsフォルダを作成し、このフォルダに先ほどエクスポートした.rivファイルを移動します。

そして、pubspec.yamlassets/を追加します。

  assets:
    - assets/

rive packageをインストールする

https://pub.dev/packages/rive

flutter pub add rive

上記のようにriveパッケージをインストールしましょう。

Flutterで.rivを利用したアニメーションを表示する

  SizedBox(
              height: 116, // Rive Editorで設定した数値にしておく
              width: 300,
              child: InkWell( // RiveAnimation.assetをタップ可能にするため
              onTap
                child: RiveAnimation.asset(
                  'assets/send.riv', // 作成した.rivを指定
                  controllers: [controller], // 
                ),
                onTap: () => _changeAnimation(), // アニメーションを切り替える処理
              ),

ここで、controllerは以下のように設定することができます。

controller = SimpleAnimation('init');

初期状態はinitという名前のアニメーションに設定しています。これはRive Editor上のAnimationsに表示されている名称と一致します。

たとえば、以下のように設定することもできます。

controller = SimpleAnimation('send');

この例では、Rive Editor上でsendという名前で設定されたアニメーションを発動できます。

したがって、Stateful WidgetのsetStateやRiverpodなどのStateを利用してコントローラーの値を変えてあげれば、自由にアニメーションを切り替えることができます。

FlutterでRive Animationを自由に切り替える

ここまでわかっていれば、自由自在にアニメーションを切り替える事ができます。

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late RiveAnimationController controller;

  //自前のSendAnimationクラスをインスタンス化
  final SendAnimation sendAnimation = SendAnimation();

  
  void initState() {
    super.initState();

    controller = sendAnimation.getController();
  }

  _changeAnimation() {
    setState(() {
      sendAnimation.changeAnimation();
      controller = sendAnimation.getController();
    });
  }

  
  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            SizedBox(
              height: 116,
              width: 300,
              child: InkWell(
                child: RiveAnimation.asset(
                  'assets/send.riv',
                  controllers: [controller],
                ),
                onTap: () => _changeAnimation(),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
enum SendAnimationTypeEnum {
  init,
  send,
}

class SendAnimation {
  SendAnimationTypeEnum type = SendAnimationTypeEnum.init;
  SimpleAnimation controller = SimpleAnimation('init');
  
  void changeAnimation() {
    switch (type) {
      case SendAnimationTypeEnum.init:
        type = SendAnimationTypeEnum.send;
        controller = SimpleAnimation('send');
        return;
      case SendAnimationTypeEnum.send:
        type = SendAnimationTypeEnum.init;
        controller = SimpleAnimation('init');
        return;
      default:
        return;
    }
  }

  getController() {
    return controller;
  }
}

今回は、クリックでアニメーションをトグルするように設定しました。しかし、バリエーションはいくつも考える事ができます。

たとえば、

  • ボタンを押す → animation → なんらかのデータをFetchしたときに戻る
  • ScrollNotifierListenerを使ってスクロールによりトリガーする
  • なんらかのValidationがFailedしたときにアニメーションする

などなど、アイデアは様々です!好きなタイミングでアニメーションを作ってみてください!

レポジトリも置いておきます。
https://github.com/obutora/rive_practice

まとめ

Riveを使うことで、簡単にFlutter上で操作可能なアニメーションを作成することができました。

https://zenn.dev/hagakun_dev/articles/d384c06318c560

既存のWidgetに対してリッチなアニメーションを付けることが目的の場合、初回表示時以前公開した easy_animateというpackageを使った方がカンタンに実装できるかと思います。

しかし、ボタン操作や他のインタラクティブな要素に対してアニメーションを設定するとき、Riveで特別なアニメーションを作成するとUXをさらに向上させることができるのではないでしょうか。

FlutterとRiveの実装として、英語学習アプリのDuolingoがあります。
このアプリは鳥のキャラクターが高頻度で登場し、ユーザーの英語学習を飽きさせないようにしています。

アプリに親近感を持ってもらう方法としてアニメーションは非常に有効な手段となりますし、冒頭で述べたようにアプリ離脱を避ける大きな手段の1つです。

もっと勉強して、ユーザーフレンドリーなアプリを作れるように頑張らなくては!では!

おまけ

https://twitter.com/hagakun_yakuzai
最近買った剃刀であごを切ってケツアゴになりました。
友達めっちゃ募集してます🙇‍♂️

Discussion