もっと!Lottie
※本記事はQiitaに投稿していた記事のexportです(元投稿日: 2019/04/05)
Lottie( http://airbnb.io/lottie/ )はAirbnb社が開発・公開しているアニメーションライブラリです。 アニメーションのjsonさえあれば、ImageViewと似た指定で簡単に扱えます。サンプルアプリ を入れてみると挙動がわかりやすいです。 jsonの作り方は他のドキュメントに任せて、Androidの実装側で色々やってみた例を紹介します。
きほん
アプリ内のassetsなどに置いたjsonを読み込む
<com.airbnb.lottie.LottieAnimationView android:id="@+id/lottie_view" android:layout_width="wrap_content" android:layout_height="wrap_content" app:lottie_fileName="hello_world.json" app:lottie_loop="true" app:lottie_autoPlay="true" />
アプリ内に置かず、URLで指定する
<com.airbnb.lottie.LottieAnimationView android:id="@+id/lottie_view" android:layout_width="wrap_content" android:layout_height="wrap_content" app:lottie_url="https://xxxxx/hello_world.json" />
もっと!
可変なURLを指定する
サーバからjsonのURLを取得して、その内容を表示させたいとき。これはxmlだけでは出来なくて、コードを書くことになります。
lottieView.setAnimationFromUrl(url)
この指定で表示はされます。しかし、URLが存在しなかったりロード出来なかったときに IllegalStateException が投げられてしまいます。 たぶんこの部分 https://github.com/airbnb/lottie-android/blob/master/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java#L66
private final LottieListener<Throwable> failureListener = new LottieListener<Throwable>() { @Override public void onResult(Throwable throwable) { throw new IllegalStateException("Unable to parse composition", throwable); } };
落ちないように次のようにしました。
LottieCompositionFactory.fromUrl(this, url) .addFailureListener { // 読み込み失敗時の処理 } .addListener { lottieView.setComposition(it) }
コードで動的に指定するときは lottieView.playAnimation()
を忘れるとアニメーションが開始しないので注意です。
アニメーションが終わったら消す
AnimatorListenerかAnimatorListenerAdapterのListenerをセットし、アニメーションの開始や終了時の処理を記述できます。
lottieView.addAnimatorListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator?) { lottieView.visibility = View.GONE } })
複数のアニメーションを連続して表示する
サーバから1つずつ表示したいアニメーションのURLを取得し、それをQueueに詰めてみることにしました。
private val lottieQueue: LinkedList<String> = LinkedList() private val animationListener = object : AnimatorListenerAdapter() { override fun onAnimationEnd(animator: Animator) { playNextLottie() } } // 〜〜〜 { // どこかでサーバから1つずつ取得する lottieQueue.add(enqueueURL) // 複数詰める playNextLottie() } // 〜〜〜 private fun playNextLottie() { val lottieUrl = lottieQueue.pollFirst() if (lottieUrl.isNullOrEmpty()) { // Queueから全てなくなったら終了 disableLottieView() // listener解除など終了処理 return } buildAndPlayLottieView(lottieUrl) } private fun buildAndPlayLottieView(url: String) { LottieCompositionFactory.fromUrl(context, url) .addFailureListener { playNextLottie() // リンク切れなどのときは何もせず次へ } .addListener { lottieView.setComposition(it) lottieView.addAnimatorListener(animationListener) lottieView.playAnimation() } }
その後、これらの処理はcom.airbnb.lottie.LottieAnimationView
を継承したCustomViewをつくって突っ込みました。
動的に取得したLottieを画面の横幅目一杯に表示する
match_parent
して伸びるのはアニメーションの背景だけだったので、scaleを設定してみました。
LottieCompositionFactory.fromUrl(this, url) .addListener { lotteCompotition -> lottieView.scale = lottieView.measuredWidth.toFloat() / lotteCompotition.bounds.width() }
アスペクト比が固定なのであれば、 app:layout_constraintDimensionRatio
で縦横比を指定して match_constraint
でもいけてました。
scaleTypeも使えますが、 centerCrop
と centerInside
しか使えないので注意です。
こまった!
おちた!
json内でフォントの指定がされており、そのフォントが見つからなかったときに落ちました。次のエラーが出ました。
Font asset not found fonts/BlackHanSans.ttf
特に文字は使っていなかったので、フォント指定のないjsonを作り直してもらいました。
でない!
ViewよりLottieが大きいと表示されませんでした。scaleで調整したりしました。
おもい!
古い端末だともっさりすることがあります。json側の作り方の方は詳しくないので、軽く作る良い方法があったら知りたいです。
おわりに
アニメーションはうまく使うとわかりやすいし楽しいです。参考になる記事などをいくつか載せておきます。良いLottieライフを!
サクッとLottieの概要がわかる記事
- lottieが大変よろしいものだった - アナログ金木犀 https://motida-japan.hatenablog.com/entry/2017/02/19/145537
jsonの作り方の話
- デザイナーとエンジニアの距離をより近づける Lottie 利用術 - DroidKaigi 2019 https://droidkaigi.jp/2019/timetable/70876
導入事例などの話
- 実践 Lottie - DroidKaigi 2019 https://droidkaigi.jp/2019/timetable/69036