見出し画像

DataBindingチュートリアル第6回 – アニメーション

第5回ではユーザーの属性が変わるたびにユーザーインターフェースが切り替わる仕組みをDataBindingで実現しました。 今回はこれをさらに改良して、切り替えのタイミングにアニメーションを挿入する方法を紹介したいと思います。

サンプルプロジェクトはこちら↓↓からダウンロードできます。

OnRebindCallback

前回のコードにアニメーションをつけるのは非常にシンプルです。まずOnRebindCallbackというものをbindingオブジェクトにaddします。

binding.addOnRebindCallback(object : OnRebindCallback<ViewDataBinding>() {
   override fun onPreBind(binding: ViewDataBinding): Boolean {
       TransitionManager.beginDelayedTransition(
           binding.root as ViewGroup
       )
       return super.onPreBind(binding)
   }
})

このようにするとBindingされたデータに変更があり、Bindしたビュー側が再評価される時にコールバックを受け取ることができます。

OnRebindCallbackクラスで受け取るコールバックのうちonPreBindというメソッドをオーバライドし、この中で、TransitionManagerbeginDelayedTransitionという関数を呼びます。
このメソッドは(こちらの公式ドキュメントに詳細が書かれていますが) 、beginDelayedTransitionを呼んでから次のビューの描画が行われるまでの間の全てのビューの変更をアニメーションさせるというメソッドです。
onPreBindはバインドしたビューの再評価が行われる前に呼ばれる関数なので、再評価の直前のここでこの関数を呼んでおけば直後に行われるビューの再評価と再描画の際にアニメーションが起きるようになります。


BindingAdapterを使ったアニメーション

OnRebindCallbackとTransitionManagerを使ったアニメーションはでは変更のあったデータにバインドされて見た目が変わる全てのビューにアニメーションが適用されます。
場合によっては、ある特定のビューだけをアニメーションしたい、またはTransitionManagerによって作られるアニメーションとは違ったアニメーションを割り当てたいケースがあるかもしれません。このような場合はBindingAdapterを使って個別にアニメショーンを加える方法があります。

まず、下のようにViewとvisibilityの内容を取得するBindingAdapterを作ります。

// ViewのVisibility変更時にフェードイン/アウトのアニメーション効果を加えるBindingAdapter
@BindingAdapter("bind:visibilityWithAnimation")
@JvmStatic
fun setVisibility(
   view: View,
   visibility: Int
) {

   //特定のクラスにだけアニメーションを適用したり外したりする場合。
   if (view is Button) {
   }

   //特定のタグのビューだけアニメーションを変えたり、外したりする場合。
   if (view.tag == "foo") {
   }

   //今のvisibilityから変化がないので何もしない
   if (view.visibility == visibility) {
       return
   }
   val startAlpha =
       if (view.visibility == View.VISIBLE) 1f else 0f
   val endAlpha = if (visibility == View.VISIBLE) 1f else 0f
   val animator = ObjectAnimator.ofFloat(
       view,
       View.ALPHA, startAlpha, endAlpha
   )
   animator.setAutoCancel(true)
   animator.duration = 1000
   animator.addListener(object : AnimatorListenerAdapter() {
       override fun onAnimationStart(anim: Animator) {
           view.visibility = View.VISIBLE
       }

       override fun onAnimationCancel(anim: Animator) {}
       override fun onAnimationEnd(anim: Animator) {
           view.alpha = 1f
           view.visibility = visibility
       }
   })
   animator.start()
}

この中で、ObjectAnimatorを使ってVISIBLEになるときは、アルファの値を1へ、VISIBLE以外の状態(INVISIBLEかGONE)に変化する時はアルファ値を0へとアニメートさせることをやっています。

android:visibilityの代わりにbind:visibilityWithAnimationというタグを使って下のようにするとこのアニメーションが適用されます。

<Button
   android:layout_width="300dp"
   android:layout_height="wrap_content"
   android:text="INVITE"
   android:onClick="@{() -> handler.onClickInvite(user)}"
   app:font="@{`Roboto-Bold.ttf`}"
   app:visibilityWithAnimation="@{user.isFriend ? View.GONE : View.VISIBLE}"
   />

BindingAdapterの先頭でViewのクラスやtagをチェックすることで特定のクラスや特定のtagのビューにだけアニメーションを適用することが可能です。

@BindingAdapter("bind:visibilityWithAnimation")
@JvmStatic
fun setVisibility(
   view: View,
   visibility: Int
) {

   //特定のクラスにだけアニメーションを適用したり外したりする場合。
   if (view is Button) {
   }

   //特定のタグのビューだけアニメーションを変えたり、外したりする場合。
   if (view.tag == "foo") {
   }

まとめ

OnRebindCallbackを実装することで、Dataをバインドしたビューの再評価直前のタイミングにコールバックを得ることができます。この時にTranslationManager.beginDelayedTransitionを使うことで、ビューの変化に簡単にアニメーションをつけることができます。

この方法を使わず、ビュー個別に自分独自のアニメーションをつけたい場合はBindingAdapterを使って実現することができます。

GitHub

DataBindingTutorialのコードはこちらのGitHubでも公開しています。

https://github.com/mizutori/AndroidDataBindingTutorial

今回のサンプルはコミットハッシュ

327c0480178e5b3439e40f7e1d8d12a35b46d93b

で保存してあります。

git clone git@github.com:mizutori/AndroidDataBindingTutorial.git
git checkout 327c0480178e5b3439e40f7e1d8d12a35b46d93b




この記事が気に入ったらサポートをしてみませんか?