Custom Alert (UIAlertView) with swift
Code tested in Swift 5 and Xcode 10
How to make your own custom Alert
I was wanting to do something similar. First of all, UIAlertView
is deprecated in favor of UIAlertController
. See this answer for the standard way to display an alert:
- How would I create a UIAlertView in Swift?
And both UIAlertView
and UIAlertController
do not really allow much customization. One option is to use some third party code. However, I discovered that it isn't that difficult to create your own Alert by displaying another view controller modaly.
The example here is just a proof-of-concept. You can design your alert any way you want.
Storyboard
You should have two View Controllers. Your second view controller will be your alert. Set the class name to AlertViewContoller
and the Storyboard ID to alert
. (Both of these are names that we defined ourselves in the code below, nothing special about them. You can add the code first if you want. It might actually be easier if you add the code first.)
Set the background color for the root view (in your Alert View Controller) to clear (or translucent black is nice for an alert). Add another UIView
and center it with constraints. Use that as your alert background and put whatever you want inside. For my example, I added a UIButton
.
Code
ViewController.swift
import UIKit
class ViewController: UIViewController {
@IBAction func showAlertButtonTapped(_ sender: UIButton) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myAlert = storyboard.instantiateViewController(withIdentifier: "alert")
myAlert.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
myAlert.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
self.present(myAlert, animated: true, completion: nil)
}
}
AlertViewController.swift
import UIKit
class AlertViewController: UIViewController {
@IBAction func dismissButtonTapped(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
}
Don't forget to hook up the outlets.
You can add an onTouchUp
event listener to the background view to dismiss the popup when the user clicks outside of it.
That's it. You should be able to make any sort of alert that you can imagine now. No need for third party code.
Here is another custom alert I made. Still ugly, but it shows more things you can do.
Other options
Sometimes there is no need to reinvent the wheel, though. I'm impressed with the third party project SDCAlertView (MIT license). It is written in Swift but you can use it with Objective-C projects as well. It offers a wide range of customability.
How would I create a UIAlertView in Swift?
From the UIAlertView
class:
// UIAlertView is deprecated. Use UIAlertController with a
preferredStyle of UIAlertControllerStyleAlert instead
On iOS 8, you can do this:
let alert = UIAlertController(title: "Alert", message: "Message", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
Now UIAlertController
is a single class for creating and interacting with what we knew as UIAlertView
s and UIActionSheet
s on iOS 8.
Edit: To handle actions:
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: { action in
switch action.style{
case .Default:
print("default")
case .Cancel:
print("cancel")
case .Destructive:
print("destructive")
}
}}))
Edit for Swift 3:
let alert = UIAlertController(title: "Alert", message: "Message", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
Edit for Swift 4.x:
let alert = UIAlertController(title: "Alert", message: "Message", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { action in
switch action.style{
case .default:
print("default")
case .cancel:
print("cancel")
case .destructive:
print("destructive")
}
}))
self.present(alert, animated: true, completion: nil)
Swift Custom UIAlertView
Something like the following should allow it. Note there quite a few improvements that could be made. For example you could use a generic for the object being deleted instead of AnyObject. You also don't necessarily need to pass it in if you pass the closure inline anyway so you could probably just remove it.
You could also make your buttons more reusable rather than hard-coding to cancel and remove but now we're getting off topic :)
class ConfirmViewController : UIViewController {
var onCancel : (() -> Void)?
var onConfirm : ((AnyObject?) -> Void)?
var objectToDelete : AnyObject?
func cancelButtonPressed() {
// defered to ensure it is performed no matter what code path is taken
defer {
dismissViewControllerAnimated(false, completion: nil)
}
let onCancel = self.onCancel
// deliberately set to nil just in case there is a self reference
self.onCancel = nil
guard let block = onCancel else { return }
block()
}
func confirmationButtonPresssed() {
// defered to ensure it is performed no matter what code path is taken
defer {
dismissViewControllerAnimated(false, completion: nil)
}
let onConfirm = self.onConfirm
// deliberately set to nil just in case there is a self reference
self.onConfirm = nil
guard let block = onConfirm else { return }
block(self.objectToDelete)
}
}
let confirm = ConfirmViewController()
confirm.objectToDelete = NSObject()
confirm.onCancel = {
// perform some action here
}
confirm.onConfirm = { objectToDelete in
// delete your object here
}
How to use custom UIAlertview in multiple ViewControllers?
I will give the answer for a simple custom alertview which is basically a modified uiviewcontroller. you can use a uiviewcontroller as a uialertviewcontroller as follow.
Simple AlertView::
The AlertVC:
import UIKit
class ErrorAlert: UIViewController {
var titlenote:String = ""
var message:String = ""
@IBOutlet weak var cancelBtn: UIButton!
@IBOutlet weak var messageHolder: UILabel!
@IBOutlet weak var imageHolder: UIImageView!
@IBOutlet weak var titleHolder: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.black.withAlphaComponent(0.7)
// Do any additional setup after loading the view.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.messageHolder.text = self.message
self.titleHolder.text = self.titlenote
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func dismiss(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
}
This viewcontroller can be reuse in any vc and any number of times.
Useage Example::
let alertController = self.storyboard?.instantiateViewController(withIdentifier: "erroralert") as! ErrorAlert
alertController.titlenote = "Invalid login"
alertController.message = "Invalid facebook account."
alertController.providesPresentationContextTransitionStyle = true
alertController.definesPresentationContext = true
alertController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
alertController.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
self.present(alertController, animated: true, completion: nil)
I have made the background of the alertviewvc semitransparent by setting the alpha value.
Actual Display ::
You can make more complex alertview by this method but for reusability you have apply some logic as the button actions will be different for different viewcontroller. Example -- Sometime you can use the alertview for logout alert or sometime for submitting a form .So in both cases the action will be different so for reusability you have to write extra logic.
Another alertView::
I hope my answer will help you.:)
present custom alert above another custom alert or uialertview
No, don't do it. From the Apple documentation: "People know that alerts notify them about problems and dangerous situations." So, you should minimize them.
https://developer.apple.com/ios/human-interface-guidelines/ui-views/alerts/
It is a intuitive behavior that alert should dismiss after pressing button. So don't change it.
By the way, in which situation you need two alerts one after another? Maybe we can help you with changing logic.
Swift UIAlertController showing custom message
Why not simply an extension
?
extension UIViewController {
func presentAlert(withTitle title: String, message : String) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: .default) { action in
print("You've pressed OK Button")
}
alertController.addAction(OKAction)
self.present(alertController, animated: true, completion: nil)
}
}
and call it with
presentAlert(withTitle: "Error", message: "error")
in any UIViewController
class
How to add an action to a UIAlertView button using Swift iOS
The Swifty way is to use the new UIAlertController and closures:
// Create the alert controller
let alertController = UIAlertController(title: "Title", message: "Message", preferredStyle: .Alert)
// Create the actions
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default) {
UIAlertAction in
NSLog("OK Pressed")
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel) {
UIAlertAction in
NSLog("Cancel Pressed")
}
// Add the actions
alertController.addAction(okAction)
alertController.addAction(cancelAction)
// Present the controller
self.presentViewController(alertController, animated: true, completion: nil)
Swift 3:
// Create the alert controller
let alertController = UIAlertController(title: "Title", message: "Message", preferredStyle: .alert)
// Create the actions
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) {
UIAlertAction in
NSLog("OK Pressed")
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel) {
UIAlertAction in
NSLog("Cancel Pressed")
}
// Add the actions
alertController.addAction(okAction)
alertController.addAction(cancelAction)
// Present the controller
self.present(alertController, animated: true, completion: nil)
Custom Alert in Swift
First of all you should never touch window
on iOS. Except for extremely rare special cases.
You can create in your .xib a view with transparent or semi-transparent background. Then you can define a protocol to present this view:
protocol AlertPresenting {}
extension AlertPresenting {
func showAlert(_ onView: UIView) {
if let alert = Bundle.main.loadNibNamed("AlertView", owner: nil, options: nil)![0] as? AlertView {
alert.translatesAutoresizingMaskIntoConstraints = false
onView.addSubview(alert)
//here define constraints
onView.bringSubviewToFront(alert)
}
}
}
Then you can use it on any viewController
:
class MyViewController: UIViewController, AlertPresenting {
func someFunction() {
showAlert(onView: self.view)
}
}
The alert will be above all the views
.
Related Topics
How to Center Align the Cells of a Uicollectionview
Filemanager Cannot Find Audio File
Uitableview Checkmark Only One Row at a Time
Set Default iOS Local Notification Style for Application
Uistackview Distribution Fill Equally
React/Rctbridgemodule.H' File Not Found
App Rejected Because of Advertisingidentifier in Facebook Sdk and Flurry Sdk
Ios9 - This Application Is Modifying the Autolayout Engine from a Background Thread -- Where
How to Store an Image in Core Data
How to Add a 'Done' Button to Numpad Keyboard in iOS
Issue with Code Autocompletion/Syntax Highlighting in Xcode 4.X
iOS Simulator Games Run Very Slow (Low Fps)
What Is Export * in Module.Modulemap File Inside Each Framework