カスタムアニメーションによるView Controllerの遷移

Satsuki Hashiba
5 min readMar 29, 2020

--

本記事では、UIViewControllerAnimatedTransitioningを用いてView Controllerをカスタムアニメーションで遷移させる方法を解説します。

トランジションのカスタマイズ方法

1. 遷移先のVIewControllerのサイズをカスタマイズする / 遷移時のアニメーションを簡易的にカスタマイズする→ こちら
2. 遷移時のアニメーションをカスタマイズする → 本記事
3. 遷移をインタラクティブにする → こちら

UIViewControllerAnimatedTransitioning

NSObjectに継承させるプロトコルで、View Controllerの遷移に対するカスタムアニメーションを実装することができます 。前回の記事で解説したUIPresentationControllerでは遷移中に利用するカスタムビューしかアニメーションを記述できませんが、UIViewControllerAnimatedTransitioningを継承したアニメータを実装することで、遷移元・遷移先のView Controllerもアニメーションさせることができます。

このプロトコルを準拠するには、以下2つのメソッドの実装が必須です。

UIViewControllerContextTransitioningの注意点

これらのメソッドでは、引数としてUIViewControllerContextTransitioningに準拠したオブジェクトが渡されます。これはView Controller間の遷移アニメーションに関する情報を提供するものですが、利用する際に2つの注意点があります。

まず1つ目は、isAnimatedをチェックすることです。この値がfalseだった場合にはアニメーションを生成すべきではありません。

2つ目の注意点は、アニメーションのcompletion handlerの中で必ずcompleteTransition(_:)を呼ぶことです。これを呼び出すことで、UIKitにカスタムアニメーションの終了を知らせることができます 。

Presented / Dismissの判定

transitionContextにはpresent時のアニメーションなのかdismiss時のアニメーションなのかを判別するパラメータが存在しません。presentとdismissの区別が必要な場合には、カスタムアニメータにisPresentedパラメータを宣言し、animateTransition(using:)で処理を分けます。

カスタムアニメータの指定

遷移先のView ControllerにUIViewControllerTransitioningDelegateを継承し、animationController(forPresented:presenting:source:)及びanimationController(forDismissed:)メソッドの返り値として渡します。この時、カスタムアニメータのisPresentedを指定します。

サンプル

以下は、幅半分のView Controllerが右からスライドするように遷移するUIPresentationControllerおよびカスタムアニメータです。(UIPresentationControllerの実装は、前回の記事とほぼ同様のため省略します)

このサンプルでは遷移先のView Controller(サイドバー)が遷移元のView Controllerの上に重なるように表示されますが、animateTransition(using:)の実装によっては遷移元のView Controllerがサイドバーの分だけ左にずれるような表示をさせることも可能です。

present時の遷移アニメーションについて、上のサンプルコードではtoView.frame.origin.x -= toView.bounds.widthと記述しています。toViewの初期位置は指定していませんが、アニメーション終了時(今回の場合はtoView.bounds.width分だけ左に移動した時)にUIPresentationControllerのframeOfPresentedViewInContainerViewで指定した場所に存在するような座標に自動で設定されているように見えます。

修正 — 2020/04/14
completeTransition(_:)に対してUIView.animatedcompletedを渡していましたが、これはUIView.animatedが完了したかどうかを表すフラグであり、遷移が完了したかどうかはわかりません。正しくはtransitionContext.transitionWasCancelledを用いて判定する必要があります。また、遷移がキャンセルされた場合には、アニメーションのために追加したview(上記のサンプルコードではtoView)をsuperviewから取り除く必要があります。サンプルコードにおいて以上2点を修正しました。

--

--

Satsuki Hashiba
Satsuki Hashiba

Written by Satsuki Hashiba

iOS Engineer 🍋 Master’s Student 🌄 Japan ⛩

No responses yet