Custom UIViewController transitions

Don’t stick to just modal and push.

Bruno Muniz
ITNEXT

--

Today we’ll implement a custom transition, scaling an UIView from half-screen up to fullscreen using UIViewControllerAnimatedTransitioning . What will happen inside this custom transition is just some simple constraint animation but we could do pretty much anything.

From this quick-n-dirty scheme I drafted up here, you can get the idea that occurs on transitions. For easiness, we’ll just use one view for each screen.

This looks stretched because of NSLayoutConstraints but in fact there’s not much here. Before we get to Presenter, notice that the screens have no idea about what we’re trying to do. The logic is completely isolated from it.

Presenter is a coordinator that implement these two functions from the UIViewControllerTransitioningDelegate protocol. All we have to do here is to pass the transition with the correct direction to each animationController(for presented/for dismissed)

All right, its time to take a look at the reason we are here: Transition.

All right, first things first — we have an enum called Direction which hold two cases, one for present and another one for dismiss. We also hold the direction so we can set it back in our presenter. When conforming to the protocol UIViewControllerAnimatedTransitioning we must implement transitionDuration and animateTransition functions. The first one simply returns a CGFloat which is the duration of the transition and the second one is the ‘big deal’.

We isolated the present and dismiss into private functions so inside the animateTransition function we just switch over the directions and call the appropriate function passing the transitionContext. Also, notice that we are storing two arrays of NSLayoutConstraints. They will hold the presented state constraints and the dismissed state constraints.

  • Using the context on the present function, we can get the view that will be presented using context.view(forKey: .to). In case we wanted to do something else prior to the transition we could also retrieve the view that will present just by changing the key to .from
  • Now that we have the view that will be presented, we add it as subview from the context.containerView which is the view that get displayed during the transition and then set the constraints for each state: presented and dismissed.
  • The last thing we need to do is purely UIView animations on the constraint and now (really) the last thing is to call completeTransition(true) in order to display the correct screen.

When dismissing, we’ll just go the other way round. Play with the constraints and voilá.

Here’s an example of what we can do with this:

--

--