にっき

社会人になった

FlutterでAirbnbのアニメーションライブラリLottieを使う

はじめに

Qiitaから移動しました。

Flutter #2 Advent Calendar 2019 4日目です。

最近FlutterでLottieを使う機会があったので、その際調べたことを忘備録も兼ねて書いていこうと思います。 Flutter/Dart自体そこまで経験がある訳ではない(1年未満な)ので間違っている箇所などあると思います。見かけたら教えてくださると幸いです。

TL;DR

  • Flutterのlottie用ライブラリはfluttieとflutter_lottieの2つがある
  • fluttieは単純に使えるができることは多くない
  • flutter_lottieは少し複雑だができることが多い
  • fluttieがiOSバイス未対応なので、現状としてはflutter_lottie一択?

Lottieとは

LottieとはAirbnbがリリースしたiOS/Android/React Native向けのアニメーションライブラリです。 After Effectで作成したアニメーションをリアルタイムでレンダリングし、静止画を使用するのと同じぐらい簡単に複雑なアニメーションを表示できるとのこと。

詳細はこちら AirbnbのアニメーションライブラリLottie(ロッティー)の使い方🎅 - @17genai | Qiita

How to use

を始める前に、monoさんによるFlutterアニメーションの解説を置いておきます。 直接関係する内容ではないですが参考になるので、未読の方は一度目を通しておくのをおすすめします。

改めて、 Lottieは公式でFlutter用のライブラリとして以下の2つを紹介しています

fluttie

使い方が単純でサクッと実装できますが複雑な操作が難しく、またiOSバイスがサポート外です。

サンプルコード

あらかじめassetにJSON形式でLottieファイルを入れておき、引数にPathを渡してあげると表示されます。

import 'package:flutter/material.dart';
import 'package:fluttie/fluttie.dart';

class MyFluttie extends StatefulWidget {
  const MyFluttie({
    @required this.path,
    Key key,
  }) : super(key: key);

  final String path;

  @override
  _MyFluttieState createState() => _MyFluttieState();
}

class _MyFluttieState extends State<MyFluttie> {
  String _path;
  Fluttie _instance;

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100,
      width: 100,
      child: FutureBuilder(
        future: _setupAnimation(),
        builder: (BuildContext context, AsyncSnapshot<FluttieAnimationController> snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.none:
            case ConnectionState.active:
            case ConnectionState.waiting:
              return CircularProgressIndicator();
            case ConnectionState.done:
              return GestureDetector(
                onTap: () {
                  snapshot.data.start();
                },
                child: FluttieAnimation(snapshot.data),
              );
          }
        },
      ),
    );
  }

  Future<FluttieAnimationController> _setupAnimation() async {
    _instance = Fluttie();
    _path = widget.path;
    final int composition =
        await _instance.loadAnimationFromAsset(_path);
    final FluttieAnimationController animationController =
        await _instance.prepareAnimation(composition);
    return animationController;
  }
}

_setupAnimation()内でassetからFluttieAnimationControllerを作成し、FluttieAnimationクラスにFluttieAnimationControllerを渡して描画します。 FluttieAnimationController.start()でアニメーションがスタート。 他にもpause(), unpause(), stopAndReset()が呼べます。

flutter_lottie

AnimationControllerを用いるため比較的複雑ですが、AnimationControllerでできることは大体できます。 ただしライブラリの更新がかなり怪しい(今年の2月末に公開されたきりほぼ更新されていない)のが難点です。

サンプルコード

fluttieと同じく、あらかじめassetにJSON形式でLottieファイルを入れておき、引数にPathを渡してあげると表示されます。

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:lottie_flutter/lottie_flutter.dart';

class MyLottieFlutter extends StatefulWidget {
  const MyLottieFlutter({
    @required this.path,
    Key key,
  }) : super(key: key);

  final String path;

  @override
  _MyLottieFlutterState createState() => _MyLottieFlutterState();
}

class _MyLottieFlutterState extends State<MyLottieFlutter> with SingleTickerProviderStateMixin {
  LottieComposition _composition;
  AnimationController _controller;

  @override
  void initState() {
    super.initState();

    _loadAsset(widget.path).then((LottieComposition composition) {
      setState(() {
        _composition = composition;
        _controller.reset();
      });
    });
    _controller = AnimationController(
      vsync: this,
    )..addListener(() => setState(() {}));
  }

  Future<LottieComposition> _loadAsset(String assetName) async {
    return await rootBundle
        .loadString(assetName)
        .then<Map<String, dynamic>>((String data) => json.decode(data))
        .then((Map<String, dynamic> map) => LottieComposition.fromMap(map));
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100,
      width: 100,
      child: FittedBox(
        fit: BoxFit.contain,
        child: GestureDetector(
          onTap: () => setState(() {
            _controller.reset();
            _controller.forward();
          }),
          child: Lottie(
            composition: _composition,
            size: Size(100, 100),
            controller: _controller,
          ),
        ),
      ),
    );
  }
}

initState()内でassetを読み込みAnimationControllerLottieCompositionをInstantiate、Lottieクラスに渡して描画します。 アニメーションの再生はAnimationControlelrreset()forward()で行っています。 AnimationControllerなのでreverse()repeat()なども使え、flottieと比べてできることの幅が広いです。

まとめ

個人的な所感ですが、fluttieがiOSバイス未対応な現時点ではflutter_lottie一択かなと感じています。 ただしfluttieの方が更新が多いので、今後のアップデートによっては用途によって使い分けができるようになりそうです。