業務で少し調べたことのメモ程度に。
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まとめ#
AndroidでViewのアニメーションを行う際にはTransition APIも選択肢の一つ
Transition APIを使ったアニメーションで、所定のタイミングで処理を実行したい場合にはTransitionクラスのaddListener関数を利用する
デフォルトで用意されているTransitionクラスはAutoTransition
TransitionListener interfaceにはTransitionListenerAdapterクラスが用意されている