fresh digitable

めんどくさかったなってことを振り返ったり振り返らなかったりするための記録

lottie-androidで気を付けたいこと(追記あり)

今回のモチベーション

  • デザイナーさんにアプリのスクショを送ったらlottieのパーツの色が少し濃いように見えるという話になった
  • 問題のパーツは、透明度の指定されたレイヤーがいくつか重なっているもので、絵が重なっている領域と重なっていない領域とがある
  • lottie-webのほうにjsonを食わせたものと見比べたら確かにAndroidのほうが濃かった。(意味があるかはわからないけど)Macのカラーピッカーで比較してみても表示環境の違い以上の差が確認できた
    • lottie-web: version. 5.5.8
  • カラーピッカーの実測値と設定値とを見比べると、
    • webのほうは絵が重なっている領域も重なっていない領域も、レイヤーに指定された透明度とRGBそれぞれの値とを掛けた値が、実測値と一致した
    • androidのほうは重なっている領域の実測値が上振れしていた
  • レイヤーのブレンドモードに実装の違いがあるのではないかと予想してコードを読んだ

手短に言うと

  • lottie-androidの仕様です
    • コードをさんざん読んで何も分からんとなったあと、DESIGNERS_NOTE.mdというファイルに書いてあるのを発見し、心が無になった
    • 子の要素を描くとき、親のレイヤーやグループに対して指定された不透明度は子の不透明度に掛け算しているとのこと*1
    • 例えば下の図でいうと左側のような図を作りたかったとしても、lottie-androidでは右側のようになってしまう

f:id:akihito104:20190928195402p:plain
lottie-web(左)とlottie-android(右)の描画の差の模式図

https://jsfiddle.net/3yLgxdqs/

  • (2019/9/29 1:53 追記) もうちょっとよく読んだら、このコミット: Fix rendering issue of translucent object overlapping (#1362) · airbnb/lottie-android@5e12628 · GitHub で親レイヤーに不透明度が指定されている場合にもoff screen renderingをやって正しい描画ができるようになる模様。次のバージョンで入るかな。
  • (2019/10/15 0:29 追記) ver. 3.1.0がリリースされました。setApplyingOpacityToLayersEnabledのドキュメントを読んでねとのこと。
    • ちなみに私のパッチも取り込まれました。大した変更でもないのにいろいろと面倒をかけてしまった。。。

そのほかの雑多なこと

  • レイヤーのブレンドモードは未実装
  • キャンバスサイズをはみ出すと涙目画質になってしまう
    • LottieDrawable.draw()の中のコメントに書いてあることによると、Androidで確保できる画面のキャッシュサイズ以上の絵を描くことはできないので、絵を一旦キャンバスの中に納まるサイズで描いた後、本来の指定された大きさに引き延ばしているとのこと
    • LottieDrawableを背景にセットするときにはBoundsの大きさに注意しよう

*1:そうなってるのはコード読んでわかってたけどそのときはそれでいいと思ってた

*2:コードを読んだからJSONも読めるようになった(読めるようになったとは言っていない)ということですね

なぜAndroidアプリをMVVMでつくるといいのか

モチベーション

  • Androidでは画面のパーツは全部のオブジェクトへの参照を持つのでリークさせたくない
  • MVCとかMVPはCやPがVへの参照を持つので、とくにAndroidでは管理をきっちりやらなければならない
  • その一方で、ActivityやFragmentのライフサイクルが複雑なので管理をきっちりやるのは難しい
  • MVVMではVMはVへの参照を持たないので、MVCとかMVPとかよりは漏れにくいはず
  • そういう理由からAndroidアプリの開発にフィットしそうな設計ということで、公式から便利なライブラリがいろいろ出ているのでその恩恵を受けられる
  • MV-WhateverはMとVの関心ごとをいかに分離するかという話なのでRepositoryとかUseCaseとかとはまた別のはなしです

実装のはなし

  • MからVに向かってデータを伝えるにはObserver-Observableパターンを使う
    • ViewModelにObservableな変数を持たせてView側から観測する
  • ObservableFieldとかでもいいけどLiveDataを使うと画面が見えていないときはViewの更新が起きないようになっているので便利
    • ObservableIntとかObservableFloatは実際の値をJavaのプリミティブ型に保持しているので自動的にNonNullだしオブジェクトが作られないのでAnimatorの値を渡してもいいかもしれない
  • AndroidにはDataBindingの仕組みがありViewとLiveData(とかObaservableXxx)とを結びつけるコードを自動生成してくれる
    • DataBindingを使わずにMVVMをやろうとするのは大変つらいと思われるのでおすすめしない
  • ViewModelはPure Java(Kotlin)のクラスばっかりになるはずなのでテストが書きやすいし実行も速い
    • ViewとViewModelのプロパティが正しくバインドされているならば、ViewModelのプロパティをテストすることでその画面のテストを行うのと同じになるはず

Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option

ある日突然怒られたりするやつです。ライブラリを新しく入れたりアップデートしたときとか。

stackoverflow.com

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = "1.8"
    }
}