关闭当前显示的所有 UIAlert控制器



有没有办法关闭当前呈现的所有UIAlertControllers?

这特别是因为从我的应用程序的任何地方和任何状态,当按下推送通知时,我需要访问某个视图控制器。

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)
    }
}

这对我有用!

编辑:适用于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)
       }
   }

您可以对UIAlertController进行子类化,将NSNotification观察器附加到每个观察器,这将触发UIAlertController子类中的一种方法来关闭警报控制器,然后在准备关闭时发布NSNotification,例如:

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)
    }
}

然后在您准备好消除警报时发布通知(在本例中,按下推送通知时(:

NSNotificationCenter.defaultCenter().postNotificationName("DismissAllAlertsNotification", object: nil)
您可以

通过以下方式关闭当前向用户显示的UIAlertController

self.dismissViewControllerAnimated(true, completion: nil)

我在 swift 4 中编写了更多通用代码,此类使用实用程序类显示警报。

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)
    }
}

以这种方式使用它

//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)

当您想要/需要在应用程序中自动关闭警报时发布通知

let DismissAllAlertsNotification = Notification.Name("DismissAllAlertsNotification")
NotificationCenter.default.post(name: DismissAllAlertsNotification, object: nil)

它们是模态的:任何时候都只有一个,它将具有完全的焦点。

你有责任创建警报,用户应该消除警报。如果需要进一步控制,则需要创建(或使用(自定义视图来显示消息堆栈。

我使用以下扩展来实现这一点,希望对您有所帮助

首先;您将有一个用于UIApplication的扩展来检索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
   }
}

第二;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)
    }
}

最新更新