Photo by Ralph (Ravi) Kayden on Unsplash
- You will be expected to be aware how to make a Single View Application in Swift
- It would be useful to be familar with UIStackView
- I connected storyboard objects to code, and used delegation within this solution
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 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!
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
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).
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()
}
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).
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
There aren't too many other files here. The Constants.swift
file contains some colours here but not that much more.
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.
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