業務で少し調べたことのメモ程度に。
AndroidでViewをアニメーションさせたいときの実装方法の一つとして、Transitionがあります。
Transition
Transitionの概要については、公式ドキュメント、もしくはyarakiさんによる下記のスライドが参考になります。
Transitionは、アニメーションの前後のViewの状態を保存、比較をして、それに応じたAnimatorを生成し実行してくれる便利なAPIです。
例えば下記のようなコードを実行すると、binding.target Viewの表示・非表示がフェードしながら切り替わります。
TransitionManager.beginDelayedTransition(binding.root) // rootとなるViewGroupを指定 binding.target.isVisible = !binding.target.isVisible // アニメーションしたいViewの描画状態を更新
beginDelayedTransition関数は魔法のような関数となっており、これを実行後にViewの表示切り替えを行うことで、よしなにアニメーションをしてくれます。
上記の例では、内部でデフォルトとして設定されているTransitionクラスを利用して動きのアニメーションを実現します。もちろんデフォルト以外の動きを実現するために、自分で独自のTransitionクラスを定義し渡すこともできます。
val myTransition = MyTransition() TransitionManager.beginDelayedTransition(binding.root, myTransition) // 第2引数にTransitionを渡す
Listenerを追加する
よくあるパターンとして、アニメーションの終了後に何らかの処理を実行したい場合があります。
Transitionが終了したタイミングでよしなに処理を行いたい場合には、TransitionクラスのaddListener関数を使って、Listenerを追加します。
以下はTransitionクラスのaddListener関数の内部実装です。
/** * Adds a listener to the set of listeners that are sent events through the * life of an animation, such as start, repeat, and end. * * @param listener the listener to be added to the current set of listeners * for this animation. * @return This transition object. */ @NonNull public Transition addListener(@NonNull TransitionListener listener) { if (mListeners == null) { mListeners = new ArrayList<>(); } mListeners.add(listener); return this; }
カスタムTransitionを定義している場合はTransition初期化時にaddListener関数を呼び出すことで問題なくListenerを追加できます。
val myTransition = MyTransition().addListener(object : Transition.TransitionListener() { ... // 関数をoverride }) TransitionManager.beginDelayedTransition(binding.root, myTransition)
では、カスタムTransitionを定義していない場合(=beginDelayedTransition関数の引数にTransitionクラスを渡さない場合)はどうすればいいのでしょうか?
そのような場合には、Transitionクラスが内部で保持している、デフォルトのTransitionクラスを初期化し、このクラスにListenerを追加できます。
デフォルトのTransitionクラスというのは、AutoTransitionというクラスです。内部実装を読むと、TransitionManagerクラスに、private staticフィールドとして定義されていることがわかります。
public class TransitionManager { ... private static Transition sDefaultTransition = new AutoTransition();
なのでこのAutoTransitionクラスを初期化して利用をすれば、問題ないです。
val transition = AutoTransition().addListener(...)
TransitionManager.beginDelayedTransition(binding.root, transition)
Tips
addListener関数には素直にTransitionListenerクラス自体を渡すこともできますが、代わりにこのListenerクラスを実装したTransitionListenerAdapterというクラスを渡すこともできます。AdapterクラスはAndroidのAPIにあるinterfaceクラスをただoverrideしただけ(独自の処理はない)のclassです。TransitionListener以外のListenerなどに対しても定義されていることがあります。
Adapterクラスがintefaceに定義されている関数をすべて空で実装しているため、このAdapterクラスを代わりに利用することで、Listenerに定義されている関数の中で、開発者がoverrideしたい関数のみをAdapterクラスを介してoverrideして利用することができます。
最終的には以下のようなコードとなりました。
val transition = AutoTransition() .addListener(object : TransitionListenerAdapter() { override fun onTransitionEnd(transition: Transition) { // do something } }) TransitionManager.beginDelayedTransition(binding.root, transition) binding.target.isVisible = !binding.target.isVisible