【Android】Bindingした値をトリガにいい感じにアニメーションする(今回の対象:背景色)


やりたいこと

「ViewModelクラスに持ってる値に応じて、Viewの背景色を変えたい。変わる時にはアニメーションしてほしい」

やったリポジトリ

実装内容の話

プラスマイナスののカウンターがあって、0だと背景グレーで、それ以外だと別の色。
この色変更をアニメーションさせたい。そんな実装をしました。

データ側

ViewModel側に色情報も持って、LiveDataに突っ込みました。

MainViewModel.kt
// ~上略~
    private val _qty = MutableLiveData(0)
    val qty: LiveData<Int> = _qty

    val cardColor: LiveData<Int> = Transformations.map(_qty) {
        when (it) {
            0 -> Color.LTGRAY
            else -> Color.CYAN
        }
    }
// ~下略~

レイアウト側

時間をかけて色を変更するBindingAdapterを定義します。たぶん今回のキモ。

BindingUtils.kt
@BindingAdapter("backgroundColor_gradually")
fun bindBackgroundColorGradually(view: View, oldColor: Int, newColor: Int) {
    if (oldColor == newColor) return
    val background = view.background
    if (background is ColorDrawable) {
        ValueAnimator.ofArgb(background.color, newColor).apply { // ここでoldColorを使うと色変化中に戻すような時に中間色が使われない
            duration = 500
            addUpdateListener { view.setBackgroundColor(it.animatedValue as Int) }
            start()
        }
    } else {
        view.setBackgroundColor(newColor)
    }
}

背景色を変えたいViewにbackgroundColor_graduallyを定義します。

main_fragment.xml
<!-- ~上略~ -->
        <com.google.android.material.card.MaterialCardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:backgroundColor_gradually="@{vm.cardColor}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">
<!-- ~下略~ -->

おわりに

本質的には「ValueAnimatorつかってみた」だけの内容になってしまった感がありますが、
いい具合に複雑にならずにViewModelからXMLへのBindingで書けたと思います。満足。

BindingAdapter関数の内容のカスタマイズとLiveDataに持つ値の対応で、
Viewの回転とか座標とかサイズとかもアニメーションできると思います。

参考