Building a Custom Transitioning for ViewController in iOS
By: Arjun Baru
Tags: Mobile, Programming, Swift, iOS, Xcode

As per the above understanding, what does this class need? Duration (for delegate), estimated final height, and whether we’re presenting or dismissing the viewController (we’ll come to this part later).

Add the below code to the class:

let estimatedFinalHeight: CGFloat

let animationDuration: TimeInterval

var isPresenting: Bool init(estimatedFinalHeight: CGFloat, animationDuration: TimeInterval, isPresenting: Bool) { self.estimatedFinalHeight = estimatedFinalHeight

self.animationDuration = animationDuration

self.isPresenting = isPresenting }

Let’s explore func animateTransition(using transitionContext: UIViewControllerContextTransitioning) .

Add the following code:

// 1

guard let fromVC = transitionContext.viewController(forKey: .from),

let toVC = transitionContext.viewController(forKey: .to) else { return } //2

let containerView = transitionContext.containerView //3

fromVC.beginAppearanceTransition(false, animated: true)

toVC.beginAppearanceTransition(true, animated: true)

//1 This line will give us both the view controllers(to and from).

//2 The container view is responsible for the animation. We add the view which will be presenting and dismissing to animate it accordingly.

//3 When we do custom presentation, our viewController ’s lifecycle doesn’t get called which will result in abrupt behaviour. It’s recommended that we never call lifecycle methods directly. This function takes care of that.

Let’s add code in order to present a view controller on top of another:

if isPresenting { // 1

toVC.view.frame.origin.y = fromVC.view.frame.maxY

containerView.addSubview(toVC.view) UIView.animate(withDuration: animationDuration, animations: { // 2

toVC.view.frame.origin.y = self.estimatedFinalHeight

fromVC.view.layer.transform =

ViewControlerScale.modelPresentationScale.transform }, completion: { _ in //3

fromVC.endAppearanceTransition()

toVC.endAppearanceTransition() transitionContext.completeTransition(!transitionContext.transitionWasCancelled)

})

}

//1 We will fix the “To be presented” ViewController at the bottom of the currently presented ViewController. Add toVC to Container view(as this is responsible for holding the presented ViewController).

//2 Within Animation we are changing the Y Axis of toVC from maxY to the desired height. Also, with the help enum , declared above, we transform our background ViewController to scale/shrink to give a 3D effect.

//3 Once we’re done with animation, we notify system so that lifecycle methods can be called properly.

If not presenting, it should be dismissing. Let’s add the else part in continuity to the above code:

else { // 1

containerView.addSubview(fromVC.view) UIView.animate(withDuration: animationDuration, animations: { // 2

fromVC.view.frame.origin.y = UIScreen.main.bounds.maxY

toVC.view.layer.transform = ViewControlerScale.reset.transform }, completion: { _ in // 3

fromVC.endAppearanceTransition()

toVC.endAppearanceTransition() transitionContext.completeTransition(!transitionContext.transitionWasCancelled)

})

}

The catch: We’re also using the same function to dismiss ViewController . At this time, we’re going from PresentedViewController (which will now be fromVC ) to presentingViewController (which will be toVC ). The tables have turned!

//1 We are translating the pop-up ViewController to the bottom before it gets dismissed. This view gets added to containerView .

//2 Reset the toVC ( PresentingViewController ) which we scaled down previously to its original scale.