iOSにおけるカスタムトランジションの実装

Satsuki Hashiba
5 min readApr 30, 2019

既存のpresentやpushにはアニメーションが実装されていますが、もう少し遅くしたいかもしれません。また、TabBarを用いた画面切り替えにはそもそもアニメーション自体が付いていません。アプリ全体の雰囲気を高めるためにも、遷移時アニメーションをカスタマイズしたい場合があります。

UIViewControllerTransitioningDelegateを用いたカスタムトランジションは、以下の2ステップで実装できます:

  1. Animatorの作成
  2. 作成したAnimatorの指定

1. Animatorの作成

UIViewControllerAnimatedTransitioningを継承したオブジェクトを作成します。ここにアニメーションのdurationと挙動を記述します。

2. 作成したAnimatorの指定

デリゲートメソッドにて、先ほど作成したAnimatorを指定します。

A. present/dismissの場合
遷移先のviewControllerにUIViewControllerTransitioningDelegateを継承し、指定のメソッドにてAnimatorを指定します。

遷移をコードで書く場合には遷移元に記述しますのでtransitionDelegateも同じところに書いてしまいそうになりますが、このデリゲートは自分自身がpresentされる時やdismissされる時のAnimatorを指定するものです。なので、遷移先に継承させます。

B. push/popの場合
自作のUINavigationControllerクラスにUINavigationControllerDelegateを継承し、指定のメソッドにてAnimatorを指定します。

C. TabBarの場合
自作のUITabBarControllerクラスにUITabBarControllerDelegateを継承し、指定のメソッドにてAnimatorを指定します。

UIViewControllerContextTransitioningとは

UIViewControllerContextTransitioningとは、UIKitによって構成されるオブジェクトが準拠しているプロトコルです。私たちが生成することはなく、AnimatorのanimateTransition:transitionDuration:で引数として渡されます。主にanimateTransition:内でアニメーションの詳細を記述する際に使用します。この中には遷移に関連するviewとviewControllerが含まれていて、以下のように取得することができます:

ただ、これから行うトランジションのpresent/dismissやpush/popを判別できる情報はこのオブジェクトには含まれていません。そのためトランジションによってアニメーションを切り替えたい場合には、先述の 2. 作成したAnimatorの指定 にてAnimatorを生成する際に、必要な情報を渡します。

UIViewControllerContextTransitioningの注意点3つ

  1. 遷移先のビューをcontainerViewに追加する

UIViewControllerContextTransitioningcontainerViewというビューを持っており、これがアニメーション中のsuperviewとして振る舞います。全ての遷移アニメーションはこのビューの上で行われます。遷移元のビューはUIKitによって自動的に追加されていますが、遷移先のビューはanimateTransition:内でaddSubviewする必要があります。

2. アニメーションでかけた加工は元に戻す

UIViewControllerContextTransitioning内のviewやviewControllerは、スナップショットではなく本物です。そのため、アニメーション終了後にはこれらにかけた加工を元に戻す処理を書く必要があります。

3. アニメーション終了時にはcompleteTransition(_:)を呼び出す

また、アニメーションの終了時には必ずcompleteTransition(_:)を呼び出さなければいけません。これもアニメーションのcompletionHandlerの中に記述しましょう。

以上でカスタムトランジションの実装は終了です。ビュー全体をアニメーションさせるだけでなく、特定の部品からズームイン/アウトするような遷移も作ることができます。また、Animatorに準拠させるプロトコルを変えることで、インタラクティブな遷移も実装することができます。

サンプルコードはこちら

参考文献

--

--