Custom UIViewController Transition using UIStoryboardSegue

The most popular way is to use UIViewControllerAnimatedTransitioning.

To do this, you must do the following:

  • Create a subclass, which can be called “XXXTransitioning”, inheriting from “NSObject” and implementing the two functions in the “UIViewControllerAnimatedTransitioning” protocol.
1
2
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval
func animateTransition(using transitionContext: UIViewControllerContextTransitioning)
  • Then:
    1. Create an instance of “XXXTransitioning” in the “ViewController “.
    2. Set transitioningDelegate = self.
    3. Extend “ViewController” with UIViewControllerTransitioningDelegate and implement:
1
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning?

dismiss

I noticed that the Storyboard Segue has a Custom option.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class XXXModalSegue: UIStoryboardSegue {
override func perform() {
let fromVC = source
let toVC = destination

let fromView = fromVC.view!
let toView = toVC.view!

let (w, h) = (UIScreen.main.bounds.width, UIScreen.main.bounds.height)

toView.alpha = 0
toView.frame = CGRect(x: w/2, y: 0, width: w, height: h)

let window = UIApplication.shared.keyWindow
window?.insertSubview(toView, aboveSubview: fromView)

UIView.animate(withDuration: 0.4, animations: {
toView.alpha = 1
toView.frame = toView.frame.offsetBy(dx: -w/2, dy: 0)
}) { (b) in

self.source.present(self.destination, animated: false, completion: nil)
// OR: self.source.dismiss(animated: false, completion: nil)
}
}
}

That’s it, no need for coding delegate and Extension. Simple and clean :)

Translated by gpt-3.5-turbo