Dim the lights on those view controllers with protocol extensions
One of the most common questions I get from students during the UI/UX portion of class is "How do I transition to a smaller view controller and dim the background behind it?”. This effect has been used all over in app design to show depth and focus, typically on a modally presented screen. The key to this is to get the background to darken in place while the next view controller is transitioning over the top of the current context. There are multiple ways you can go about this, and in my opinion and from answers on various boards it seems that the Internet has chosen the most verbose of them.
Do I really need to implement custom transitions? No.
The transitioning API is very powerful, and can let you do incredible animations while transitioning. It is also not the easiest to implement, and designing for reuse or bidirectionality is a challenge, especially if you are new to iOS app development. There are also a ton of blog posts on this, since custom transitions using the transitioning API have been around since the days of iOS 7.
If all you want to do is present a view controller modally with one of the three built-in transition styles (cover vertical, flip horizontal, or cross dissolve), then you’ve come to the right place, my friend. We are going to use the power of Swift 2.0 protocol extensions coupled with the same old segues you’ve been using for years.
Here's the completed project files in case you want to follow along.
Step 1: Create and extend a “Dimmable” protocol
First, we create a new empty protocol called Dimmable, and extend it using Swift 2's new protocol extensions feature to include implementation for a function called dimmer( ). This function is responsible for turning the dim background on/off, choosing the color, animation speed, and the degree of how dim (alpha'd) the background should be. We also create an enum type called Direction for convenience.
Because we are creating the dim view programmatically, we need to apply Auto Layout in code so that we are still adaptive to app changes. Don't freak out... it's not that bad. Check out the Visual Format Language reference, as well as posts on the topic here.
Step 2: Configure storyboard components
We have a really simple set up here. Two custom view controllers with a segue "modally presented" in between them.
The transparency happens due to the configuration of the second view controller. First off, the view you want to show should be smaller than the root view of the controller, otherwise there will be no room to see underneath. Second, you must make the root view "clear" colored, and set the entire view controller presentation style to "Over Current Context". This is key, and will allow the parent view controller's view to persist even after the transition is complete.
Step 3: Implement segue code
Now all we need is a way to trigger our dimmer( ) method. Segue and unwind segue methods will allow the primary view controller to control its own look. Let's use the prepareForSegue override, and an unwind segue. Both are placed in the PrimaryViewController.
Just remember that you must type out the unwind segue @IBAction code before you can wire up the "Close" button on the SecondaryViewController.
Step 4 (optional): Makey nicey
I added some rounded corners, shadows, and borders. No biggie.
Step 5: Build and run 🚀
Pros:
- No delegates to worry about
- No animator object to write
- Available to any view controller you choose by simply conforming to Dimmable
Cons:
- You are stuck with the three modal transition styles
- Yes there is a fourth style (page curl). Don't try it… 🤕
Q: Can't I do this with just straight up Swift extensions on UIViewController?
A: Yes, but then it wouldn't be very Swifty, would it? Also, this way lets you pick and choose which view controllers should conform to Dimmable, instead of all view controllers just getting a new method whether you use it or not.
The final project files can be found up on GitHub here.
Hope this saves you some time someday. In the end, it should get you the effect you want for a fraction of the price. If it doesn’t, you always have custom transitions you can fall back to for the more advanced animation handling.