Android: Lottie Animation を任意の位置とサイズにオーバーレイ(ViewOverlay)表示させる
2021/12/06:編集メモ:Lottie 3.4.0 では以下の方法でうまく動作していますが、 Lottie 3.6.0 ではうまく動作していないかもしれません。Lottie 3.6.0 以降ではこの記事に記載した方針と ViewGroupOverlay + View (foreground = LottieDrawable) の組み合わせでうまく動かせました。今後あらためて検証する時間が取れたら情報を整理し、 ViewGroupOverlay での対応を記載予定です。
TL;DR
- Lottie Animation を ViewOverlay に表示することで、View Tree に影響を与えずにアニメーション表示させる
- ViewOverlay は Android 4.3 以上で使えます
やりたいことと問題点
Button タップを起点として Lottie でリッチなアニメーションを表示させるとき、レイアウト上の Button のサイズよりも広い範囲にアニメーションを表示させたいことがあります。
たとえば、 Twitter Android アプリのお気に入り Button UI はタップするとハートマークよりも広い範囲にアニメーションが表示されています。
これを XML レイアウト上で表現すると以下のようなレイアウトとなりますが、この方法では Button の周囲の View と LottieAnimationView が被ることがあったり、見た目上の margin と XML での margin 指定がズレており、レイアウトの配置に苦労します。レイアウトの重なり順にも問題があるため、LottieAnimationView を最前面に移動させる工夫も必要になります。
このレイアウトで A も C もアニメーションを付けることになったら XML が大変なことになりそうです...
アニメーションを XML で表現したときの構成:
<LinearLayout...>
<Button.../>
<FrameLayout...
android:layout_marginTop="-14dp"
android:layout_marginStart="-10dp"
android:layout_marginEnd="-10dp">
<Button.../>
<com.airbnb.lottie.LottieAnimationView.../>
</FrameLayout>
<Button..../>
</LinearLayout>
解決策: Lottie Animation を ViewOverlay へ表示する
Android 4.3 以上であれば、ViewOverlay を利用できます。
ViewOverlay は View の最前面に存在しているレイヤーで、任意の View か Drawable を ViewOverlay に表示することができます。
ViewOverlay は View ごとに存在します。ViewOverlay は描画のみに使われるため、タップイベントなどには反応しません。
Activity や Fragment 画面遷移時の Shared Element Transition も ViewOverlay により実現されています。
ViewOverlay の使い方
- 任意の View に対して
view.overlay
でアクセスできる - オーバーレイ表示するタイミングで
view.overlay.add(Drawable)
または、view.overlay.add(View)
により、描画したい要素を追加する- Drawable の描画位置は drawable.bounds で指定する
- オーバーレイ表示が不要になったら、
view.overlay.remove()
で要素を削除する-
Any view added to the overlay should be removed when it is no longer needed or no longer visible.
https://developer.android.com/reference/android/view/ViewGroupOverlay#add(android.view.View) - 不要になったら削除すべきだそうです
-
ViewOverlay + LottieDrawable 実装
後述の PositionedLottieDrawable を用いて、以下のように実装します。
// アニメーションの起点となる Button
private val button: ToggleButton = ...
// オーバーレイ表示したい View。 Button の Parent である場合が多い
private val targetView: ViewGroup = (button.parent as! ViewGroup)
private val drawable = PositionedLottieDrawable()
private val compositionTask: LottieTask<LottieComposition>
init {
drawable.addAnimatorListener(object: Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator?) = Unit
override fun onAnimationEnd(animation: Animator?) {
// アニメーション終了で Drawable を Overlay から削除
targetView.overlay.remove(drawable)
// アニメーション終了後の状態 (Toggle ON/OFF) で表示
button.alpha = 1f
}
override fun onAnimationCancel(animation: Animator?) = Unit
override fun onAnimationRepeat(animation: Animator?) = Unit
})
compositionTask = LottieCompositionFactory
.fromRawRes(context, R.raw.lottie_animation)
.addListener {
// 非同期で Lottie JSON を読み込み、drawable へ設定する
drawable.composition = it
}
}
fun clickButton(checked: Boolean) {
if (checked) {
// checked = true へ移行するアニメーション処理
// より安全な実装とするには、ここで drawable.composition が読み込み済みであることを確認してください
// 読み込みが完了していなければ compositionTask の終了を待ってからアニメーションを実行する必要があります
// アニメーション中は Button を非表示
// 表示したままでよければ alpha を変更する必要はない
// アニメーション中にも Button タップ判定を拾いたいため、visibility ではなく alpha 変更
button.alpha = 0f
// アニメーション Drawable の座標を計算する
// このサンプルでは Button とアニメーションが中央合わせとなるように計算している
drawable.x = (button.x - (drawable.composition.bounds.width() - button.width) / 2)
drawable.y = (button.y - (drawable.composition.bounds.height() - button.height) / 2)
targetView.overlay.add(drawable)
drawable.playAnimation()
} else {
// checked = false へ移行する実装は省略
// button.alpha やアニメーションの処理を実装する
// こちらにもアニメーションが必要なら、checked = true のアニメーションを停止してから
// あたらしくアニメーションを開始したりする
}
}
PositionedLottieDrawable ワークアラウンド
Lottie 3.6.1 時点で、LottieDrawable は bounds で指定した座標に描画してくれない問題があります。
以下の PositionedLottieDrawable により、描画座標を修正します。
class PositionedLottieDrawable : LottieDrawable() {
var x: Float = 0f
var y: Float = 0f
override fun draw(canvas: Canvas) {
canvas.save()
canvas.translate(x, y)
super.draw(canvas)
canvas.restore()
}
}
ViewOverlay + LottieAnimationView ではうまく動かない
Lottie 3.6.1 時点で、LottieAnimationView は ViewOverlay に追加しても正しくアニメーションしません。
-
https://github.com/airbnb/lottie-android/blob/v3.6.1/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java#L613
- LottieAnimationView.playAnimation() は View.isShown() のときのみアニメーションを開始するように実装されている
- OverlayView に追加された View は View.isShown() が true となることはないため、アニメーションが開始されることはない
Author And Source
この問題について(Android: Lottie Animation を任意の位置とサイズにオーバーレイ(ViewOverlay)表示させる), 我々は、より多くの情報をここで見つけました https://qiita.com/irgaly/items/4bf58116a3ffac7a5f45著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .