Swift: Custom UIAlertController view

Simon Hessner picture Simon Hessner · Apr 6, 2018 · Viewed 12.8k times · Source

The docs say that subclassing UIAlertController is bad

The UIAlertController class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified.

So what is the recommended way to have an alert that shows not only a title, message and some buttons but also other stuff like ProgressBars, Lists, etc.?

In my special case I would like to have two different alerts, one that shows a ProgressBar and one that shows a list of error messages.

Currently I am trying to add the ProgressView manually and set constraints:

func getProgressAlert(onAbort: @escaping () -> ()) -> UIAlertController {
    let alert = UIAlertController(title: "Test", message: "Test", preferredStyle: .alert)

    let abort = UIAlertAction (title: "Abort", style: UIAlertActionStyle.cancel) { _ in
        onAbort()
    }
    alert.addAction(abort)

    let margin:CGFloat = 8.0
    let rect = CGRect(x:margin, y:72.0, width: alert.view.frame.width - margin * 2.0 , height:2.0)
    self.progressView = UIProgressView(frame: rect)
    self.progressView!.setProgress(0.0, animated: false)
    self.progressView!.tintColor = UIColor.blue
    alert.view.addSubview(self.progressView!)
    self.progressView!.translatesAutoresizingMaskIntoConstraints = false
    self.progressView!.widthAnchor.constraint(equalTo: alert.view.widthAnchor, multiplier: 1.0).isActive = true
    self.progressView!.heightAnchor.constraint(equalToConstant: 5.0).isActive = true
    self.progressView!.topAnchor.constraint(equalTo: alert.view.topAnchor).isActive = true
    self.progressView!.leftAnchor.constraint(equalTo: alert.view.leftAnchor).isActive = true       

    return alert
}

I don't think this is the way this should be done as manually defining constraints is very prone to errors on different devices. For example, the current code just shows the progress bar on the top of the alert view, but I want it to be shown between the message and the abort button.

Answer

Oliver Atkinson picture Oliver Atkinson · Apr 6, 2018

The view hierarchy for this class is private and must not be modified.

This is pretty much the nail in the coffin for this API. If you try hack it, you will cause yourself a lot of pain trying to support it across different iOS versions.

If want to have custom controls on an alert you will have to write a custom UIViewController subclass and mimic the API as best as you can whilst adding your new functionality (if you do not want to do this, there will be examples available on GitHub).

Some examples: