Creating an Adaptive UIAlertControllerStyle

Action sheets are a great way of presenting a set of options to users. Apple uses them extensively throughout iOS, and they are very easy to create during development by instantiating a UIAlertController with an action sheet style. There are two styles available, .actionSheet and .alert.

That’s all well and good on an iPhone, but when you test an action sheet on an iPad, results often look a little out of place. Sometimes, the action sheet doesn’t display correctly, with an incorrect height. When it does display correctly, something just doesn’t ‘feel’ right. You might begin to wonder if we actually want the same behaviour in an iPad context.

A great port of call when facing UI problems like this is to observe how Apple handles the same issue. They’ve likely put a lot of thought and effort into this already, so there’s no point reinventing the wheel. A little digging shows that Apple very infrequently uses an action sheet on an iPad, instead presenting the same options using an alert view - i.e. the same UIAlertController, except with a .alert style instead of a .actionSheet style. This is shown in the below screenshots. It’s a simple solution, and one that shouldn’t be too tricky to implement. Great!

UIAlertControllers


Implementing a solution

What we’d like to do is display an alert view when being run in an iPad context, and an action sheet everywhere else. Chances are we may need to do this more than once across whatever app we’re building, so it seems a little silly to write the same logic every time we want to display an action sheet.

It would be nice if there was a third UIAlertControllerStyle enum value, perhaps called .adaptiveActionSheet. To get the desired behaviour, we would only need to replace our usage of .actionSheet with .adaptiveActionSheet. Unfortunately, we can’t add a new enum value, but we can create a solution that provides almost identical functionality:

extension UIAlertControllerStyle {
    static var adaptiveActionSheet: UIAlertControllerStyle {
        return UIDevice.current.userInterfaceIdiom == .pad ? .alert : .actionSheet
    }
}

Under the hood, our adaptive action sheet style is not really an enum value, although it may appear as such to an outside user. It is a computed static variable, that resolves to either .actionSheet or .alert depending on context - which is exactly the behaviour we are after.