Skip to content

Latest commit

 

History

History
 
 

CustomAlertView

Create a Custom UIAlertView in Swift

Design it yourself!

Photo by Ralph (Ravi) Kayden on Unsplash
Photo by Ralph (Ravi) Kayden on Unsplash

Prerequisites:

Terminology

UIWindow: The basic container for an application's content on screen. iOS Apps usually have one (not always (there can be more than one), that is, usually)

This project

This is a project that creates a custom UIView that is:

  • Customizable
  • Locks the user interface

The second of these is especially important as when the UIView is displayed it is good practice to prevent a user from being able to interact with the underlying interface - they should only be able to interact with the alert itself!

result

The approach

A new storyboard has been created to store the interface of the alert. I placed a UIStackView into the view to make adding further buttons possible

sb

Both buttons have an outlet from the storyboard, so then can be accessed from AlertViewController.swift.

The UITextView is more of an example than anything else, giving us a reason to copy the text back from the presented view to the host UIViewController - but there are plenty of uses for this (a search, for instance).

Because in this case I've set up the interface using the storyboard it isn't too interesting (take a look at the repo for the implementation).

Conforming to a delegate

The custom AlertViewController will conform to a delegate called AlertsDelegate:

protocol AlertsDelegate {
    func textValue(textFieldValue: String)
}

The idea of this being that we can pass the String value back to the presenting ViewController.

This of course means that we need to have an AlertsDelegate property within the AlertViewController

var delegate : AlertsDelegate?

which can then be called later (I've called it from func textViewDone(_ sender: UITextField) , for example dragged from the storyboard outlet ) which can then be called:

@IBAction func textViewDone(_ sender: UITextField) {
    delegate?.textValue(textFieldValue: inputTextView.text ?? "")
    sender.resignFirstResponder()
}

and of course the caller UIViewController needs to conform to the delegate, I have done so using an extension to keep the code together and as some people would say, "clean"

extension ViewController: AlertsDelegate {
    func textValue(textFieldValue: String) {
        // use the String
    }
}

Then I decided to remove this custom view from the superview by using self.view.removeFromSuperView() which can be implemented using the following:

@IBAction func cancelButtonPressed(_ sender: UIButton) {
    self.view.removeFromSuperview()
}

Present the ViewController to the Window

However we are adding the AlertViewController to the UIWindow, which means that we can lock the interface.

extension AlertViewController {
    func presentToWindow() {
        guard let window = UIApplication.shared.windows.filter({$0.isKeyWindow}).first else {fatalError("Called before Windows setup")}
        let newFrame = CGRect(x: 0, y: 0, width: window.frame.width, height: window
            .frame.height)
        self.view.frame = newFrame
        window.addSubview(self.view)
    }
}

The guard statement makes sure that the window is avaliable before we try to add the view - now however the fatalError will throw an error in any case (perhaps meaning that there is an argument that there is no real point in prodicing this fatalError as the App would crash at this point in any case).

Adding the custom alert from the host view controller

This can be a little tricky - since the following code is added (in my implementation) in the func viewDidAppear(_ animated: Bool) function. The reason for this is that the UIWindow needs to be setup, and this can only be guarenteed after the full interface is visible to the user.

This is acceptable since an alert will usually be presented to the user according to some user action - which can only take place once the host view controller is visible to the user

alert = UIStoryboard(name: Constants.alertStoryBoard, bundle: nil).instantiateViewController(withIdentifier: Constants.alerts.mainAlert) as? AlertViewController
alert?.title = "Enter your task"
alert?.presentToWindow()
alert?.delegate = self

Other files

There aren't too many other files here. The Constants.swift file contains some colours here but not that much more.

Beware

I have changed the colours in the AlertViewController.swift file, so if you change them in Alerts.storyboard they may not reflect unless you change the code in the former.

But please, do, aways remember: take care of your user interface as your users take care of you.

Conclusion

Taking care of the interface is really important, and alert view is one of those. But how can you make such a view entirely custom?

This article has given you some indication of how you can create such a custom view, and I hope this gives you some idea of how to do just that and how you can progress in your own project.  Good luck!

I hope this article has been of help to you, and you can see the code from this is included in the attached Repo to get the whole lot in one go!

If you've any questions, comments or suggestions please hit me up on Twitter