iOS reusable popups and alerts presentation

Dima Kegeles
The Startup
Published in
4 min readMay 27, 2020

Picture yourself starting a new project and requirements coming up to make some small window sliding from bottom.

Piece of cake, right? We can’t use UIAlertController because it has to be fully customizable. We can’t use 3rd party libs because they are always limiting us in specific ways. So maybe we’ll make some base class that has the show and dismiss methods with sliding animation. If you think this solution is trivial, think again. Some developers would create a view, constraints, animations, buttons actions, all inside view controller. This view has zero reusability or maintainability.

Then you overhear designer saying we will also be needing different sized popups, with other animations. Some will have background fading presentation. This background can block user taps and optionally close the popup. Others will be small, more like a tooltip.

Fast forward a couple of months into the future, and you have tons of conditions inside the base class and three layers of subclasses of your popups. How to handle these cases with minimal effort and maximal flexibility?

There are two types of popups to my knowledge. Background interaction blocking and not. In this article, I will show a way to isolate and reuse their presentation logic.

Background blocking popups.

UIKit has given us the best way to handle these popups, and it’s called UIViewControllerTransitioningDelegate. It has a few parts, but once you write it, you shorten your development time. Peculiarly, I didn’t encounter tutorials that explain how to use this for everyday and straightforward things like popups.

Let’s start with PopupPresentationManager, subclass of UIViewControllerTransitioningDelegate. We can make this delegate a property of view controller, which allows us to avoid duplicating conformance methods in other view controllers.

It has two parts. 1. UIPresentationController: responsible for size and origin of the view. And also for dimming view presentation. 2. UIViewControllerAnimatedTransitioning: does main animation.

Before we talk about these heavier parts, let’s look how we would create and use popup like that. Create UnicornPopup, subclass of UIViewController. Also make nib with same name and owner. Don’t forget to set that owner view property.

To present it, we need to simply set its transitioningDelegate.

let popup = UnicornPopup()popup.transitioningDelegate = popup.presentationManagerpopup.modalPresentationStyle = .custompresent(popup, animated: true)

You can see how we can reuse this presentationManager in another similar popups.

Now let’s create DimmedPopupPresentationController, subclass of UIPresentationController. It will add dimming view when presentation of view controller begins.

We said that it determines size and origin of popup. But how can view controller pass it? One way is through argument in initializer. Another is to use preferredContentSize property, which every view controller has. All what is left for popup is to tell UIPresentationController how much size should it occupy on the screen. Also we need to take care of user taps on background dimming view. Sometimes we want it to dismiss the popup and sometime we don’t. Let’s create DimmingViewTappedProtocol. If view controller conforms to it, then it will have this kind of behaviour.

Let’s update UnicornPopup with DimmingViewTappedProtocol conformance and set preferredContentSize.

All right! To the last part. SlideInPresentationAnimator, which applies animation on frame property of presented/dismissed view controller. You can get very creative with animations. Change alpha, transforms, scale. Or simulate transition of views from one screen to another. It’s up to you.

Wow, that’s it? Yes! We moved presentation logic outside of the view. And with that we now can switch different parts like popup size, origin and animations without rewriting all the logic from scratch. We can even use this popup as full sized view controller because its presentation is part of UIKit flow.

And the result.

Non-blocking alerts

To show non blocking view above the view controller we can add subview or add view controller as a child. I prefer to work with child view controllers because their life cycle is more convenient, in my opinion.

Typically you would subclass base class to reuse the show and dismiss methods. It aint much but it’s honest work. I like to avoid subclassing when possible. Base classes usually end up as a pile of lots of unnecessary variables and conditions. So by avoiding subclassing you make it more maintainable. Let’s use protocol AlertPopupBase. Conforming view controller can pass its size to the show method by implementing alertFrame.

Let’s implement SexyFishAlert conforming to AlertPopupBase. Like in previous example, create nib, set its owner to SexyFishAlert and define view and outlets.

Usage:

//make reference in view controller
var
sexyFishAlert: SexyFishAlert?
sexyFishAlert = SexyFishAlert()sexyFishAlert?.show(in: self, title: "Hi darling, I am a fish")

Conclusion

I am sure these solutions are not suitable for every possible scenario. This is not the point. But rather to cover your most common needs and stay flexible at the same time.

--

--