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アニメーションの解説を置いておきます。 直接関係する内容ではないですが参考になるので、未読の方は一度目を通しておくのをおすすめします。
- Flutterのお手軽にアニメーションを扱えるAnimated系Widgetをすべて紹介 - Flutter 🇯🇵 - Medium
- FlutterのTransition系アニメーションWidgetをすべて紹介 - Flutter 🇯🇵 - Medium
改めて、 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を読み込みAnimationController
とLottieComposition
をInstantiate、Lottie
クラスに渡して描画します。
アニメーションの再生はAnimationControlelr
のreset()
とforward()
で行っています。
AnimationController
なのでreverse()
やrepeat()
なども使え、flottieと比べてできることの幅が広いです。
まとめ
個人的な所感ですが、fluttieがiOSデバイス未対応な現時点ではflutter_lottie一択かなと感じています。 ただしfluttieの方が更新が多いので、今後のアップデートによっては用途によって使い分けができるようになりそうです。
Discordで減衰0%なのに通話中に他アプリケーションの音量が下がる問題
症状
- 8/12のアプデ以降Discordでボイスチャットチャンネルに入ると他アプリケーションの音量が小さくなった.
- なおDiscordの設定の減衰(ATTENUATION)は0%.
解決
- Redditで同様の問題を発見.
Discord turning down other programs (NOT ATTENUATION) from discordapp
ASMRはいいぞ(kosen13s' Advent Calendar 2016)
kosen13s' アドベントカレンダー20日目のAmpです。
ほんと書くことがなさ過ぎてめっちゃ苦しい。
最近(といっても1年ぐらい)はまってるASMRについてちょっと布教もとい紹介していきます。
続きを読む
Make10
#kosen13sのSlack用にBotkit(Node.js)とHerokuを使ってmake10botを作成したのでそれについてちょこっと.
↑10分で作ったicon
経緯
twitterでしゅーぱか。さんが10つくったーをやっていたのを見かけ何人か乗っかる(5/10)
↓
プチブームになりその日の内に#make10-trainingなるチャンネルがSlackにできる
↓
手動で出題しているのを見てこれbotにしたら面白そうじゃね?
↓
Pythonの勉強ついでにやって見るかー
↓
これBotkit使ってJavaScriptで書いた方が楽なのでは?
↓
できました←今ここ
ソースコード
基本はBotkitのテンプレを流用.
元々出題のみにしようと思っていたんだけど,いろいろ検索して見るとアルゴリズムがいろいろ落ちていたので答え合わせの機能も追加.
JavaScript書くのは初めてだったけど案外何とかなった.(処理が美しくないのは仕様)
書いてからHerokuへのアップロードとか設定その他はこの辺を参考にごにょごにょ...
一番詰まったのはローカルテストの時.
環境整えコードを書き終えいざテストと
> token=YOUR_API_TOKEN node bot.js
をcmdに投げた所,
'token'は、内部コマンド外部コマンド、
操作可能なプログラムまたはバッチファイルとして認識されていません。
とのメッセージが.
色々調べた所Windows環境では
>set token=YOUR_API_TOKEN
>node bot.js
でやる必要があるらしい.
やっぱりこういうことやろうとするとLinux環境が欲しくなるなぁ...
それと今更だけど今回エディタを変えました.
元々SublimTextを使っていたんだけどAtomが良くなってると言う話を小耳に挟んでいたことを思い出し,思い切って導入.
いやぁいいね.
日本語がインライン編集できるのは強い.
プラグインの設定も直感的で分かりやすいし.
ぼけ~っとしながら書いてたら1時間も経ってた.
遅筆すぎるだろ...
眠くてめんどくさくなってきたのでこの辺りで終わり.
気が向いたら続き書く.(きっと書かない)
P.S.
そういやPhotoshopvio.netさんが復活しましたね.
ありがてぇありがてぇ...
P.P.S.
なんとか今週中に書けた...
ブログ始めました
今更ながらブログ始めました(n回目)
今度こそ、今度こそは本当に三日坊主にならないようにやっていけたら良いなぁ…。
さて、こうやって書き始めたは良いものの特に書くことが思い浮かばないので、何で今更になってブログを始めたのかその理由をちょこっと。
一つ目の理由としては、単純に周りに感化されたって事。
先日(4/30)、高専カンファレンス*1lol(通称lolカンファ)が兵庫県の明石高専であった。
今でこそ茨香祭カンファの実行委員に入っているけど、実を言うと私が高専カンファの存在を知ったのは前回の100カンファで、それまでそんなものをやっているなんて露とも知らなかった。
当時Twitterで某KWNK君とか某HUT先輩とか某OKYN先輩とかが話していたのを見て「はえ~そんなんやってるんだ(他人事)」とか言ってた気がする。
それからまぁかくかくしかじかまるまるうまうまあんなことやこんなことがあって今は茨香祭カンファの実行委員になってたりするのだけれど…。
閑話休題。
まぁそんな感じでlolカンファがあったのだけれど、残念ながら私は行っていない。
ぼかして言えば経済的理由。ぶっちゃけて言えば金がねぇ。
たしかLT発表すれば交通費援助するよみたいなのがあった気もするけど、話せる内容が無かった。
そう、何も無かったのだ。
高専に入って3年経って自分の中では色々やってきたつもりではいたけど、いざこういう場になって何か話そうと思っても何も浮かばなかった。
このままではまずい。
何がまずいって、高専は云わばぬるま湯みたいなもんだって言うのはよく聞く話。
この環境で自発的に何もせずに居たら、いざ卒業就職進学ってなった時に自分には何も無いってことになりかねない。
普通に高校に行って、進学あるいは就職していった元同級生達に対してアドバンテージが無いどころかマイナスしか残らないのはもちろんの事、同じ高専に入って精力的に活動していた人達とは天と地ほどの差ができてしまう。
実際、今回のlolカンファのUSTを見ていて自分の同期や後輩達が色々と面白いことを発表していたりした。
彼らに負けないようにというのは今はまだ難しくても、まずはどうにか食らい付いていけるように頑張っていきたい。
とはいっても、まだ自分が何をしたいのかというのははっきりしていないので、これから自分は何が出来て何が出来なくて何がしたいのかを考えていくのにこのブログを活用していきたいと思う。
長くなったけど次は二つ目の理由。
こっちは単純で、長文を書くことに慣れる為。
私は文芸部に所属している。
ほぼ名前だけで作品すらほとんど出していないいわば幽霊部員だけど。
いろいろとネタはあるけど如何せん字書きに慣れていないのでネタだけが先行してしまって思うように書けていない。
実際この文章も所々おかしい所があったりすると思う。
折角なのでこの機会に文を書くことに慣れていけたら、あわよくば作品を出せたらいいなといった感じ。
そんな理由でブログを始めようと思った訳だけど…。
考えながら書いていたので予定より長くなったかなと思ったけど、実際それほど長くも無かった。
やっぱり思考とアウトプットの感覚にズレがある感じ。
こればっかりは慣れるしかないかなぁ…。
あと文体がバラバラでチグハグな印象。
これも慣れかな。
とりあえずは週一回以上の更新を目安に。
10月の茨香祭カンファまでにそれなりに形にするのを目標に頑張っていこうと思う。
更新滞ってたらTwitter辺りでケツ叩いてくれると嬉しいな。