【问题标题】:Dismiss all UIAlertControllers currently presented关闭当前呈现的所有 UIAlertControllers
【发布时间】:2015-02-20 19:22:30
【问题描述】:

有没有办法关闭当前显示的所有 UIAlertController?

这特别是因为在我的应用程序的任何地方和任何状态下,当按下推送通知时,我都需要访问某个 ViewController。

【问题讨论】:

  • all UIAlertControllers 是什么意思?所有的 UIAlertController 都呈现了吗?
  • @CeceXX 显示的任何 UIAlertController。编辑标题和文本以指定
  • 所以你不想展示 UIAlertController 或者你想解雇那些展示的人?
  • 我想关闭当前显示的 UIAlertControllers。
  • 查看我的 Github UIAlertController 项目,我使用队列集中了 UIAlertController 的显示,您可以轻松修改代码以从那里发布通知

标签: ios swift uiwindow uialertcontroller


【解决方案1】:
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 14 吗?我尝试了几种方法,但没有一种方法有效:(
  • 不错。只是为了最新的 swift 将 ".keyWindow" 替换为 ".windows.first(where: \.isKeyWindow)"
【解决方案2】:

您可以将UIAlertControllers 子类化,将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)

【讨论】:

  • @Vov4yk 我在发布之前测试了这段代码,它对我有用。
  • @Vov4yk 但还要注意,我从未修改过该子类中 UIAlertController 的任何内容...我只是添加了一个新方法,即 hideAlertController。
  • 你有没有向appStore提交过这样的解决方案?我害怕被拒绝,因为子类化
  • @Vov4yk 文档状态:“此类的视图层次结构是私有的,不得修改。”但是我的解决方案没有修改视图层次结构,所以我不明白为什么应用程序审查会有问题。文档还指出,“UIAlertController 类旨在按原样使用,不支持子类化。”但由于我的解决方案有效,UIAlertController 显然支持这种实际上不会改变视图结构的子类化。
  • 查看我的 Github UIAlertController 项目,我使用队列集中了 UIAlertController 的显示,您可以轻松修改代码以从那里发布通知。
【解决方案3】:

您可以通过这种方式关闭当前呈现给用户的UIAlertController

self.dismissViewControllerAnimated(true, completion: nil)

【讨论】:

    【解决方案4】:

    它们是模态的:在任何时候都只会有一个,并且会全神贯注。

    创建警报是您的责任,并且应该由用户解除警报。如果您需要进一步控制,则需要制作(或使用)自定义视图来显示一堆消息。

    【讨论】:

      【解决方案5】:

      我在 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)
      

      【讨论】:

      • 这是一个在实现自动注销功能时非常有用的代码。应用程序自动重定向到登录屏幕,但屏幕上仍保留警报。
      【解决方案6】:

      我使用以下扩展来实现这一点,希望它可以帮助你

      首先;你将有一个 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)
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-11-15
        • 2015-02-09
        • 1970-01-01
        • 2018-04-19
        • 1970-01-01
        • 1970-01-01
        • 2016-02-11
        • 2022-01-27
        相关资源
        最近更新 更多