wkewbview alert dialog not showing on ipad - ios

I use a WKWebView.
Alert dialog works normally on iPhone, but is not visible on iPad. How can I fix this?
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: #escaping () -> Void) {
let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action) in
completionHandler()
}))
if UIDevice.current.userInterfaceIdiom == .pad {
if let popoverPresentationController = alertController.popoverPresentationController {
popoverPresentationController.sourceView = self.view
popoverPresentationController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
popoverPresentationController.permittedArrowDirections = []
}
} else {
self.present(alertController, animated: true, completion: nil)
}
}

In case of iPad you are not presenting the ViewController inside the if - let.
Move the self.present(alertController, animated: true, completion: nil) outside the else block.
if UIDevice.current.userInterfaceIdiom == .pad {
if let popoverPresentationController = alertController.popoverPresentationController {
popoverPresentationController.sourceView = self.view
popoverPresentationController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
popoverPresentationController.permittedArrowDirections = []
}
}
self.present(alertController, animated: true, completion: nil)
As a side-note, check if the alertController.popoverPresentationController is not nil

Related

My Camera crash on ipad 12.1.4 but works fine on iphone

I am using the camera to take photo, it is working fine in iphone, but it crashes when i run it on ipad.
#IBAction func uploadPhotoButtonPressed(_ sender: UIButton) {
let camera = Camera(delegate_: self)
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let takePhoto = UIAlertAction(title: "Take Photo", style: .default) { (alert: UIAlertAction!) -> Void in
camera.PresentPhotoCamera(self, canEdit: true)
}
let sharePhoto = UIAlertAction(title: "Photo Library", style: .default) { (alert: UIAlertAction!) -> Void in
camera.PresentPhotoLibrary(self, canEdit: true)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (alert : UIAlertAction!) -> Void in
print("Cancel")
}
optionMenu.addAction(takePhoto)
optionMenu.addAction(sharePhoto)
optionMenu.addAction(cancelAction)
self.present(optionMenu, animated: true, completion: nil)
}
I think your error in UIAlertController because in iPad you need to pass source view.
Please check UIAlertController code for iPad
if let popoverController = yourAlert.popoverPresentationController {
popoverController.sourceView = self.view //to set the source of your alert
popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0) // you can set this as per your requirement.
popoverController.permittedArrowDirections = [] //to hide the arrow of any particular direction
}
You can check this code also in your simulator, please check first and resubmit your build.
Since Apple announce iOS app should run proper in ipad as well. so, we need to make sure when we capture photo from camera and select from photo library we also need to update code for iPad regarding UIImagePickerViewController. I am attaching code which works in both iPhone and iPad.
let actionSheetController: UIAlertController = UIAlertController(title: "Select Photo", message: "", preferredStyle: .actionSheet)
let cancelActionButton: UIAlertAction = UIAlertAction(title: "Cancel", style: .cancel) { action -> Void in
print("Cancel")
}
actionSheetController.addAction(cancelActionButton)
let saveActionButton: UIAlertAction = UIAlertAction(title: "Photolibrary", style: .default)
{ action -> Void in
self.picker.allowsEditing = true
self.picker.sourceType = .photoLibrary
self.present(self.picker, animated: true, completion: nil)
}
actionSheetController.addAction(saveActionButton)
let deleteActionButton: UIAlertAction = UIAlertAction(title: "Camera", style: .default)
{ action -> Void in
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera)
{
self.picker.allowsEditing = true
self.picker.sourceType = .camera
self.present(self.picker, animated: true, completion: nil)
}
}
actionSheetController.addAction(deleteActionButton)
if let popoverController = actionSheetController.popoverPresentationController {
popoverController.sourceView = self.view
popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
popoverController.permittedArrowDirections = []
}
self.present(actionSheetController, animated: true, completion: nil)

Loading overlay causes issues when task is too short

I'm using a loading modal pretty much according to this topic:
Loading an "overlay" when running long tasks in iOS
I use the same code in several ViewControllers, so I created an extension:
extension UIViewController {
func showLoading() {
let alert = UIAlertController(title: nil, message: "Please wait...", preferredStyle: .alert)
let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
loadingIndicator.hidesWhenStopped = true
loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
loadingIndicator.startAnimating();
alert.view.addSubview(loadingIndicator)
present(alert, animated: false, completion: nil)
}
func hideLoading() {
if ( presentedViewController != nil && !presentedViewController!.isBeingPresented ) {
dismiss(animated: false, completion: nil)
}
}
}
I typically use the code like this:
self.showLoading()
callNetwork() { response in
DispatchQueue.main.async {
self.hideLoading()
....
}
}
If the network call takes 0.5s or more, everything works fine. The issue is if the network is too fast. Then I'll get an error similar to this one:
Warning: Attempt to dismiss from view controller <UINavigationController: 0x7ff581830a00> while a presentation or dismiss is in progress!
And the modal won't get dismissed.
The best solution I can come up with is something like this (super class instead of extension as extensions can't have variables):
class LoadingViewController: UIViewController {
var shouldDismissImmediately = false
func showLoading() {
shouldDismissImmediately = false
let alert = UIAlertController(title: nil, message: "Please wait...", preferredStyle: .alert)
let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
loadingIndicator.hidesWhenStopped = true
loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
loadingIndicator.startAnimating();
alert.view.addSubview(loadingIndicator)
present(alert, animated: false) {
if (self.shouldDismissImmediately) {
self.dismiss(animated: false, completion: nil)
}
}
}
func hideLoading() {
if ( presentedViewController != nil && !presentedViewController!.isBeingPresented ) {
dismiss(animated: false, completion: nil)
} else {
shouldDismissImmediately = true
}
}
}
Can anyone think of a better solution? This one just doesn't feel right. Maybe I'm doing something fundamentally wrong. Like - should I even present such a dialog when waiting for a network response? Is there a better way of making the user to wait? I need the user to be aware that something is happening and in the same time, I need him not to be able to press any buttons in the UI.
extension UIViewController {
func showLoading(finished: #escaping () -> Void) {
let alert = UIAlertController(title: nil, message: "Please wait...", preferredStyle: .alert)
let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
loadingIndicator.hidesWhenStopped = true
loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
loadingIndicator.startAnimating();
alert.view.addSubview(loadingIndicator)
present(alert, animated: false, completion: finished)
}
func hideLoading(finished: #escaping () -> Void) {
if ( presentedViewController != nil && !presentedViewController!.isBeingPresented ) {
dismiss(animated: false, completion: finished)
}
}
}
self.showLoading(finished: {
callNetwork() {
DispatchQueue.main.async {
self.hideLoading(finished: {
// done
})
}
}
})

Why is my keyboard being loaded whenever I load my UIImagePickerController view?

I have a UIActionSheet for selecting between the camera or the photo library to embed an image into a UITextView but for whatever reason it's loading the keyboard. I force close the keyboard on press of the left button of the bar surrounding the UITextView but when I press photo library I opens and closes the keyboard before pushing to the image picker VC.
override func didPressLeftButton(sender: AnyObject?) {
let cameraMenu = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)
let photoLibrary = UIAlertAction(title: "Photo Library", style: .Default, handler: { (UIAlertAction) in
self.openPhotoLibrary()
})
let takePhoto = UIAlertAction(title: "Open Camera", style: .Default, handler: { (UIAlertAction) in
self.textView.endEditing(true)
self.openCamera()
})
let cancel = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
cameraMenu.addAction(photoLibrary)
cameraMenu.addAction(takePhoto)
cameraMenu.addAction(cancel)
self.presentViewController(cameraMenu, animated: true, completion: nil)
}
func openPhotoLibrary() {
imagePicker.sourceType = .PhotoLibrary
imagePicker.allowsEditing = false
presentViewController(imagePicker, animated: true, completion: nil)
}
func openCamera(){
imagePicker.sourceType = .Camera
imagePicker.showsCameraControls = true
presentViewController(imagePicker, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
// Image resizing
let textViewWidth: CGFloat = self.textView.frame.size.width - 20
let percentResize = textViewWidth / pickedImage.size.width
let toBeExportedHeight = pickedImage.size.height * percentResize
let resizedImage = ImageManipulationManager.sharedInstance.resizeImage(exportedWidth: Int(textViewWidth),exportedHeight: Int(toBeExportedHeight), originalImage: pickedImage)
// Storage into TextView
let attachment = NSTextAttachment()
attachment.image = resizedImage
let attString = NSAttributedString(attachment: attachment)
textView.textStorage.insertAttributedString(attString, atIndex: textView.selectedRange.location)
pastedImageLocations.append(textView.selectedRange.location)
textView.selectedRange.location = textView.selectedRange.location + 1
textView.textStorage.insertAttributedString(NSAttributedString(string: "\n"), atIndex: textView.selectedRange.location)
textView.selectedRange.location = textView.selectedRange.location + 1
textView.font = UIFont.systemFontOfSize(16.0)
// Image Caching
if let data = UIImageJPEGRepresentation(pickedImage, 0.50) {
socketMessages.append(["data": data])
haneke.set(value: data, key: String(unsafeAddressOf(attachment.image!)))
print("Image cached as \"\(String(unsafeAddressOf(attachment.image!)))\"")
}
}
dismissViewControllerAnimated(true, completion: nil)
self.textView.becomeFirstResponder()
}
Found the solution.
I had to change
dismissViewControllerAnimated(true, completion: nil)
self.textView.becomeFirstResponder()
to
dismissViewControllerAnimated(true) {
self.textView.becomeFirstResponder()
}
You can do some changes by adding this -
override func didPressLeftButton(sender: AnyObject?) {
let cameraMenu = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)
let photoLibrary = UIAlertAction(title: "Photo Library", style: .Default, handler: { (UIAlertAction) in
self.view.endEditing(true) //**------ Add this
self.openPhotoLibrary()
})
let takePhoto = UIAlertAction(title: "Open Camera", style: .Default, handler: { (UIAlertAction) in
self.view.endEditing(true) //**------ Add this
self.openCamera()
})
let cancel = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
cameraMenu.addAction(photoLibrary)
cameraMenu.addAction(takePhoto)
cameraMenu.addAction(cancel)
self.presentViewController(cameraMenu, animated: true, completion: nil)
}

Ask user to choose photo from photo library or camera with swift2

I want the user to choose a photo from his photo library or camera. I couldn't find any example of it. I want to prompt the user with something like UIAlertView.
My code works fine with photo library.
#IBAction func selectLeftPhoto(sender: AnyObject) {
flag = 1
let myPickerController = UIImagePickerController()
myPickerController.delegate = self;
myPickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
self.presentViewController(myPickerController, animated: true, completion: nil)
}
#IBAction func selectRightButton(sender: AnyObject) {
flag = 2
let myPickerController = UIImagePickerController()
myPickerController.delegate = self;
myPickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
self.presentViewController(myPickerController, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage
if flag == 1 {
leftImage.image = pickedImage
let imageData = UIImageJPEGRepresentation(pickedImage!, 0.5)
let base64String = imageData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
photo1 = base64String
}else if flag == 2 {
rightImage.image = pickedImage
let imageData = UIImageJPEGRepresentation(pickedImage!, 0.5)
let base64String = imageData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
photo2 = base64String
}
dismissViewControllerAnimated(true, completion: nil)
}
My user interface :
I want to prompt the user to choose from the photo library or camera after clicking the select photo button.
let alert:UIAlertController=UIAlertController(title: "Choose Image", message: nil, preferredStyle: UIAlertControllerStyle.ActionSheet)
let cameraAction = UIAlertAction(title: "Camera", style: UIAlertActionStyle.Default)
{
UIAlertAction in
self.openCamera()
}
let gallaryAction = UIAlertAction(title: "Gallary", style: UIAlertActionStyle.Default)
{
UIAlertAction in
self.openGallary()
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel)
{
UIAlertAction in
}
// Add the actions
picker?.delegate = self
alert.addAction(cameraAction)
alert.addAction(gallaryAction)
alert.addAction(cancelAction)
// Present the controller
if UIDevice.currentDevice().userInterfaceIdiom == .Phone
{
self.presentViewController(alert, animated: true, completion: nil)
}
else
{
popover=UIPopoverController(contentViewController: alert)
popover!.presentPopoverFromRect(btnClickMe.frame, inView: self.view, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
}
let optionMenu = UIAlertController(title: nil, message: "Choose Option for Image", preferredStyle: .ActionSheet)
// 2
let cameraAction = UIAlertAction(title: "Camera", style: .Default, handler: {
(alert: UIAlertAction!) -> Void in
flag = 1
let myPickerController = UIImagePickerController()
myPickerController.delegate = self;
myPickerController.sourceType = UIImagePickerControllerSourceType.Camera
self.presentViewController(myPickerController, animated: true, completion: nil)
})
let photoGalleryAction = UIAlertAction(title: "Photo Li", style: .Default, handler: {
(alert: UIAlertAction!) -> Void in
flag = 2
let myPickerController = UIImagePickerController()
myPickerController.delegate = self;
myPickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
self.presentViewController(myPickerController, animated: true, completion: nil)
})
//
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: {
(alert: UIAlertAction!) -> Void in
println("Cancelled")
})

Dismiss all UIAlertControllers currently presented

Is there a way to dismiss all UIAlertControllers that are currently presented?
This is specifically because from anywhere and any state of my app, I need to get to a certain ViewController when a push notification is pressed.
func dismissAnyAlertControllerIfPresent() {
guard let window :UIWindow = UIApplication.shared.keyWindow , var topVC = window.rootViewController?.presentedViewController else {return}
while topVC.presentedViewController != nil {
topVC = topVC.presentedViewController!
}
if topVC.isKind(of: UIAlertController.self) {
topVC.dismiss(animated: false, completion: nil)
}
}
This worked for me!
Edit: for iOS 13+
func dismissAnyAlertControllerIfPresent() {
guard let window = windows.first(where: { $0.isKeyWindow }),
var topVC = window.rootViewController?.presentedViewController else {return}
while topVC.presentedViewController != nil {
topVC = topVC.presentedViewController!
}
if topVC.isKind(of: UIAlertController.self) {
topVC.dismiss(animated: false, completion: nil)
}
}
You could subclass your UIAlertControllers, attach NSNotification observers to each which would trigger a method within the UIAlertController subclass to dismiss the alert controller, then post an NSNotification whenever you're ready to dismiss, ex:
class ViewController: UIViewController {
func presentAlert() {
// Create alert using AlertController subclass
let alert = AlertController(title: nil, message: "Message.", preferredStyle: UIAlertControllerStyle.Alert)
// Add observer to the alert
NSNotificationCenter.defaultCenter().addObserver(alert, selector: Selector("hideAlertController"), name: "DismissAllAlertsNotification", object: nil)
// Present the alert
self.presentViewController(alert, animated: true, completion:nil)
}
}
// AlertController subclass with method to dismiss alert controller
class AlertController: UIAlertController {
func hideAlertController() {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
Then post the notification whenever you're ready to dismiss the alert (in this case, when the push notification is pressed):
NSNotificationCenter.defaultCenter().postNotificationName("DismissAllAlertsNotification", object: nil)
You can dismiss an UIAlertController that is currently being presented to the user this way:
self.dismissViewControllerAnimated(true, completion: nil)
I have written more generic code in swift 4,
This class shows alerts using utility class.
import UIKit
let APP_ORANGE_COLOR = UIColor(red: 1.000, green: 0.412, blue: 0.000, alpha: 1.00)
extension UIAlertController {
#objc func hideAlertController() {
self.dismiss(animated: false, completion: nil)
}
}
class AlertUtility: UIViewController {
static func showAlert(title: String!, message : String!, viewController: UIViewController) {
let alert = UIAlertController(title: title, message: message ,preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("ok", comment: "ok"), style: UIAlertActionStyle.cancel, handler: nil))
alert.view.tintColor = APP_ORANGE_COLOR
NotificationCenter.default.addObserver(alert, selector: #selector(alert.hideAlertController), name: DismissAllAlertsNotification, object: nil)
viewController.present(alert, animated: true, completion: nil)
}
static func showAlertAutoDismiss(title: String!, message : String!) -> Void {
//let appDelegate = UIApplication.shared.delegate as! AppDelegate
// the alert view
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let topWindow = UIWindow(frame: UIScreen.main.bounds)
topWindow.rootViewController = UIViewController()
topWindow.windowLevel = UIWindowLevelAlert + 0.8
topWindow.makeKeyAndVisible()
topWindow.rootViewController?.present(alert, animated: true, completion: {})
// change to desired number of seconds (in this case 5 seconds)
let when = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline: when){
// your code with delay
alert.dismiss(animated: true, completion: nil)
topWindow.isHidden = true
}
}
static func showAlert(title: String!, message : String!) -> Void {
//let appDelegate = UIApplication.shared.delegate as! AppDelegate
// the alert view
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let topWindow = UIWindow(frame: UIScreen.main.bounds)
topWindow.rootViewController = UIViewController()
topWindow.windowLevel = UIWindowLevelAlert + 1
topWindow.makeKeyAndVisible()
topWindow.rootViewController?.present(alert, animated: true, completion: {})
alert.addAction(UIAlertAction(title: NSLocalizedString("ok", comment: "ok"), style: UIAlertActionStyle.cancel, handler: {(_ action: UIAlertAction) -> Void in
// continue your work
// important to hide the window after work completed.
// this also keeps a reference to the window until the action is invoked.
topWindow.isHidden = true
}))
NotificationCenter.default.addObserver(alert, selector: #selector(alert.hideAlertController), name: DismissAllAlertsNotification, object: nil)
alert.view.tintColor = APP_ORANGE_COLOR
}
static func showGenericErrorMessageAlert(viewController: UIViewController) {
let alert = UIAlertController(title: NSLocalizedString("error", comment: ""), message: NSLocalizedString("generic.error.message", comment: "") ,preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("ok", comment: "ok"), style: UIAlertActionStyle.cancel, handler: nil))
alert.view.tintColor = APP_ORANGE_COLOR
viewController.present(alert, animated: true, completion: nil)
NotificationCenter.default.addObserver(alert, selector: #selector(alert.hideAlertController), name: DismissAllAlertsNotification, object: nil)
}
static func showComingSoonAlert(viewController: UIViewController) {
// the alert view
let alert = UIAlertController(title: "", message: NSLocalizedString("coming.soon", comment: ""), preferredStyle: .alert)
viewController.present(alert, animated: true, completion: {})
// change to desired number of seconds (in this case 5 seconds)
let when = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline: when){
// your code with delay
alert.dismiss(animated: true, completion: nil)
}
NotificationCenter.default.addObserver(alert, selector: #selector(alert.hideAlertController), name: DismissAllAlertsNotification, object: nil)
}
// Show alert view with call back
static func showAlertWithCB(title: String, message: String, isConditional: Bool, viewController: UIViewController, completionBlock: #escaping (_: Bool) -> Void) {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
alert.view.tintColor = APP_ORANGE_COLOR
// Check whether it's conditional or not ('YES' 'NO, or just 'OK')
if isConditional
{
alert.addAction(UIAlertAction(title: NSLocalizedString("cancel", comment: ""), style: UIAlertActionStyle.cancel, handler: { (action: UIAlertAction) in
alert.dismiss(animated: true, completion: nil)
completionBlock(false)
}))
alert.addAction(UIAlertAction(title: NSLocalizedString("yes", comment: ""), style: UIAlertActionStyle.default, handler: { (action: UIAlertAction) in
alert.dismiss(animated: true, completion: nil)
completionBlock(true)
}))
}
else
{
alert.addAction(UIAlertAction(title: NSLocalizedString("ok", comment: "ok"), style: UIAlertActionStyle.default, handler: { (action: UIAlertAction) in
alert.dismiss(animated: true, completion: nil)
completionBlock(true)
}))
}
NotificationCenter.default.addObserver(alert, selector: #selector(alert.hideAlertController), name: DismissAllAlertsNotification, object: nil)
viewController.present(alert, animated: true, completion: nil)
}
static func showAlertWithTextField(viewController : UIViewController,completionBlock: #escaping (_: Bool, String) -> Void) {
//1. Create the alert controller.
let alert = UIAlertController(title: "Report Event?", message: "", preferredStyle: .alert)
alert.view.tintColor = APP_ORANGE_COLOR
//2. Add the text field. You can configure it however you need.
//AlertUtility.addte
alert.addTextField { (textField) in
let heightConstraint = NSLayoutConstraint(item: textField, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 50)
textField.addConstraint(heightConstraint)
textField.placeholder = "Enter report reason here"
textField.tintColor = APP_ORANGE_COLOR
textField.autocapitalizationType = .sentences
}
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { [weak alert] (_) in
// Force unwrapping because we know it exists.
completionBlock(true,"")
//print("Text field: \(textField.text)")
}))
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "Submit", style: .default, handler: { [weak alert] (_) in
let textField = alert?.textFields![0] // Force unwrapping because we know it exists.
completionBlock(true,(textField?.text)!)
//print("Text field: \(textField.text)")
}))
// 4. Present the alert.
viewController.present(alert, animated: true, completion: nil)
let textField = alert.textFields![0]
let v = UIView.init(frame: textField.frame)
textField.addSubview(v)
v.frame = textField.frame
v.bounds = textField.bounds
v.backgroundColor = APP_ORANGE_COLOR
v.superview?.bringSubview(toFront: v)
}
}
Use it in this way
//sample code - use in your view controller
AlertUtility.showAlertWithCB(title: NSLocalizedString("alert", comment: "") , message: (error)!, isConditional: false, viewController: self, completionBlock: { (yes) in
//Your actions on callback
self.popToPreviousController()
})
AlertUtility.showAlert(title: ALERT_TITLE, message: message, viewController: self)
Post notification when you want/need to auto dismiss alerts in app
let DismissAllAlertsNotification = Notification.Name("DismissAllAlertsNotification")
NotificationCenter.default.post(name: DismissAllAlertsNotification, object: nil)
They are modal: there will only be one of them at any time and it will have full focus.
It is your responsibility to create your alerts and it is the user that should be dismissing them. You need to make (or use) a custom view to display a stack of messages if you need further control.
I used the following extension to achieve this, I hope it may help you
First; you will have an extension for UIApplication to retrieve the RootViewController
extension UIApplication {
static func topViewControllerInNavigationStack(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let navigationController = controller as? UINavigationController {
return topViewControllerInNavigationStack(controller: navigationController.visibleViewController)
}
if let tabController = controller as? UITabBarController {
if let selected = tabController.selectedViewController {
return topViewControllerInNavigationStack(controller: selected)
}
}
if let presented = controller?.presentedViewController {
return topViewControllerInNavigationStack(controller: presented)
}
return controller
}
}
Second; extension for UIAlertViewController
extension UIAlertController {
static func dismissPresentedAlertViewController() {
let viewController = UIApplication.topViewControllerInNavigationStack()
guard let isKindOf = viewController?.isKind(of:
UIAlertController.classForCoder()), isKindOf else {
return
}
viewController?.dismiss(animated: false, completion: nil)
}
}

Resources