iOS
Swift

UIViewControllerAnimatedTransitioningを使って画面遷移アニメーションを作る

More than 3 years have passed since last update.


概要

UIViewControllerAnimatedTransitioningを使うと簡単に画面遷移アニメーションを作れます。

まず、UIViewControllerAnimatedTransitioningプロトコルを適用したクラスを作ります(これが画面遷移の実装内容となります)。

ポイントだけ以下に示します。


Animator.swift

class Animator: NSObject, UIViewControllerAnimatedTransitioning {

func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
// アニメーションの時間(duration)を返します。
return 1.0
}

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
// ここでアニメーションの具体的な内容を書きます。
let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)
let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)

UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0, options: .CurveEaseInOut, animations: { () -> Void in
// アニメーションの具体的な内容
}) { (finished) -> Void in
// 完了後の処理
transitionContext.completeTransition(true)
}
}
}


そして、 遷移先 のViewControllerでUIViewControllerTransitioningDelegateを適用し、以下のように書くと自作の画面遷移ができるようになります(UINavigationControllerを使わない場合)。


SecondViewController.swift

class SecondViewController: UIViewController, UIViewControllerTransitioningDelegate {

let kAnimator = Animator()

override func viewDidLoad() {
super.viewDidLoad()

self.transitioningDelegate = self // delegateにselfを設定
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}

@IBAction func buttonTapped(sender: UIButton) {
dismissViewControllerAnimated(true, completion: nil)
}

// MARK: - UIViewControllerTransitioningDelegate

func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
// この画面に遷移してくるときに呼ばれるメソッド
return kAnimator
}

func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
// この画面から遷移元に戻るときに呼ばれるメソッド
return kAnimator
}
}


UINavigationControllerを使うときは 遷移元 のViewControllerに以下のように書くと遷移できます。


ViewController.swift

class ViewController: UIViewController {

let kAnimationController = FadeAnimationController()
override func viewDidLoad() {
super.viewDidLoad()
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}

func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return kAnimationController
}
}



上のテンプレートに沿って、実際にpush(show)のような簡単な画面遷移を実装してみます。


Animator.swift

class Animator: NSObject, UIViewControllerAnimatedTransitioning {

let kMovedDistance: CGFloat = 70.0 // 遷移元のviewのずれる分の距離
let kDuration = 0.3
var presenting = false // 遷移するときtrue(戻るときfalse)

func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
return kDuration
}

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)
let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)

// 遷移するときと戻るときとで処理を変える
if presenting {
presentTransition(transitionContext, toView: toVC!.view, fromView: fromVC!.view)
} else {
dismissTransition(transitionContext, toView: toVC!.view, fromView: fromVC!.view)
}
}

// 遷移するときのアニメーション
func presentTransition(transitionContext: UIViewControllerContextTransitioning, toView: UIView, fromView: UIView) {
let containerView = transitionContext.containerView()
containerView.insertSubview(toView, aboveSubview: fromView) // toViewの下にfromView

// 遷移先のviewを画面の右側に移動させておく。
toView.frame = CGRectOffset(toView.frame, containerView.frame.size.width, 0)

UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0.05, options: .CurveEaseInOut, animations: { () -> Void in
// 遷移元のviewを少し左へずらし、alpha値を下げて少し暗くする。
fromView.frame = CGRectOffset(fromView.frame, -self.kMovedDistance, 0)
fromView.alpha = 0.7

// 遷移先のviewを画面全体にはまるように移動させる。
toView.frame = containerView.frame
}) { (finished) -> Void in
fromView.frame = CGRectOffset(fromView.frame, self.kMovedDistance, 0) // 元の位置に戻す
transitionContext.completeTransition(true)
}
}

// 戻るときのアニメーション
func dismissTransition(transitionContext: UIViewControllerContextTransitioning, toView: UIView, fromView: UIView) {
let containerView = transitionContext.containerView()
containerView.insertSubview(toView, belowSubview: fromView) // fromViewの下にtoView

// 上と逆のことをする。
toView.frame = CGRectOffset(toView.frame, -kMovedDistance, 0)

UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0, options: .CurveEaseInOut, animations: { () -> Void in
fromView.frame = CGRectOffset(fromView.frame, containerView.frame.size.width, 0)
toView.frame = CGRectOffset(toView.frame, self.kMovedDistance, 0)
toView.alpha = 1.0
}) { (finished) -> Void in
transitionContext.completeTransition(true)
}
}
}


この例では、フラグを使って遷移するときと戻るときとでアニメーションを変化させています。

そのため、遷移先のviewでは以下のように、フラグを操作します。


SecondViewController.swfit

...

// MARK: - UIViewControllerTransitioningDelegate

func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
kAnimator.presenting = true // 遷移してくるときにtrueにする

return kAnimator
}

func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
kAnimator.presenting = false // 遷移元に戻るときにfalseにする

return kAnimator
}
}


このようにすると、以下のようにシンプルな画面遷移になります。

Preview

上で作成したものはGitHubにあげてあります。