无论视图层次结构如何,都要在顶部显示UIAlertController

53

我想创建一个帮助类,用于展示UIAlertController。由于它是一个辅助类,我希望它能够在任何视图层次结构中使用,而且不需要关于视图的任何信息。我可以显示警告,但当警告被取消时,应用程序崩溃并出现以下错误:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
reason: 'Trying to dismiss UIAlertController <UIAlertController: 0x135d70d80>
 with unknown presenter.'

我正在使用以下代码创建弹出窗口:

guard let window = UIApplication.shared.keyWindow else { return }
let view = UIView()
view.isUserInteractionEnabled = true
window.insertSubview(view, at: 0)
window.bringSubview(toFront: view)
// add full screen constraints to view ...

let controller = UIAlertController(
  title: "confirm deletion?",
  message: ":)",
  preferredStyle: .alert
)

let deleteAction = UIAlertAction(
  title: "yes",
  style: .destructive,
  handler: { _ in
    DispatchQueue.main.async {
      view.removeFromSuperview()
      completion()
    }
  }
)
controller.addAction(deleteAction)

view.insertSubview(controller.view, at: 0)
view.bringSubview(toFront: controller.view)
// add centering constraints to controller.view ...

当我点击yes时,应用程序会崩溃并且处理程序在崩溃之前没有被触发。我无法呈现UIAlertController,因为这将取决于当前视图层次结构,而我希望弹出窗口是独立的。

编辑:Swift解决方案 感谢@Vlad提供的想法。似乎在单独的窗口中操作要简单得多。所以这里是一个可行的Swift解决方案:

class Popup {
  private var alertWindow: UIWindow
  static var shared = Popup()

  init() {
    alertWindow = UIWindow(frame: UIScreen.main.bounds)
    alertWindow.rootViewController = UIViewController()
    alertWindow.windowLevel = UIWindowLevelAlert + 1
    alertWindow.makeKeyAndVisible()
    alertWindow.isHidden = true
  }

  private func show(completion: @escaping ((Bool) -> Void)) {
    let controller = UIAlertController(
      title: "Want to do it?",
      message: "message",
      preferredStyle: .alert
    )

    let yesAction = UIAlertAction(
      title: "Yes",
      style: .default,
      handler: { _ in
        DispatchQueue.main.async {
          self.alertWindow.isHidden = true
          completion(true)
        }
    })

    let noAction = UIAlertAction(
      title: "Not now",
      style: .destructive,
      handler: { _ in
        DispatchQueue.main.async {
          self.alertWindow.isHidden = true
          completion(false)
        }
    })

    controller.addAction(noAction)
    controller.addAction(yesAction)
    self.alertWindow.isHidden = false
    alertWindow.rootViewController?.present(controller, animated: false)
  }
}
12个回答

1
 func windowErrorAlert(message:String){
    let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
    let window = UIWindow(frame: UIScreen.main.bounds)
    window.rootViewController = UIViewController()
    let okAction = UIAlertAction(title: "Ok", style: .default) { (action) -> Void in
        alert.dismiss(animated: true, completion: nil)
        window.resignKey()
        window.isHidden = true
        window.removeFromSuperview()
        window.windowLevel = UIWindowLevelAlert - 1
        window.setNeedsLayout()
    }

    alert.addAction(okAction)
    window.windowLevel = UIWindowLevelAlert + 1
    window.makeKeyAndVisible()

    window.rootViewController?.present(alert, animated: true, completion: nil)
}

在所有视图的顶部创建一个UIAlertController,并将焦点返回到您的rootViewController,同时也要解除警报。

1
以下代码适用于iOS 13以及早期版本:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myVC = storyboard.instantiateViewController(withIdentifier: "MyVC") as! MyViewController
            
myVC.view.backgroundColor = .clear
myVC.modalPresentationStyle = .overCurrentContext
            
self.present(popup, animated: true, completion: nil)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接