在iOS中想在不依赖任何ViewController的情况下显示UIAlertController,在适配iOS13之前的写法是如下:
public func hhShowViewController(_ animated:Bool,completion: (() -> Void)?) {
let popWindow = UIWindow(frame:UIScreen.main.bounds)
popWindow.rootViewController = UIViewController()
popWindow.backgroundColor = UIColor.clear
popWindow.rootViewController?.view.backgroundColor = UIColor.clear
popWindow.windowLevel = UIWindow.Level.alert
popWindow.makeKeyAndVisible()
popWindow.rootViewController?.present(self, animated: animated, completion: completion)
}
其实很简单就是新创建一个UIWindow然后新建一个UIViewController设置为新UIWindow的rootViewController,然后使用这个Controller把UIViewController present出来,但发现在iOS13.0及以上版本就有问题了,弹框会出来一下,但是很快就又消失了,这个是个大bug,后来经过翻资料找到了解决方式,写法是新建一个类继承UIAlertController来,然后每次需要显示Alert的时候在类内缓存一下UIWIndow的实例,在弹框消失的时候置空就可以了。
import UIKit
public class HHAlertViewController: UIAlertController {
private var alertWindow:UIWindow?
public func showAlert(animated:Bool, completion:(()->Void)?) {
alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow?.rootViewController = UIViewController()
alertWindow?.windowLevel = UIWindow.Level.alert + 1
alertWindow?.makeKeyAndVisible()
alertWindow?.rootViewController?.present(self, animated: animated, completion: completion)
}
public override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
alertWindow = nil
}
}
对比两种代码是,第一种是在UIViewController的扩展里写的方法没法缓存UIWindow的实例,导致于刚显示出来又被很快回收了,造成的显示不正常。
补充一下:在写完这篇文章后我在用UIVIewController作为popover的时候这种写法会出现UIViewController内部的所有UI控件都无点击事件,经过一番尝试发现把新生成的UIWindow的isUserInteractionEnabled设置成false就可以了,我没有细究这个问题,我感觉应该是层级关系。下面贴出这个时候修正过的代码
import UIKit
open class HHConvenientVC: UIViewController {
private var alertWindow:UIWindow?
public func showVC(animated:Bool, completion:(()->Void)?) {
alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow?.rootViewController = UIViewController()
alertWindow?.isHidden = false
alertWindow?.windowLevel = UIWindow.Level.alert + 1
alertWindow?.makeKeyAndVisible()
alertWindow?.isUserInteractionEnabled = false //这行代码是解决这个事的重点
alertWindow?.rootViewController?.present(self, animated: animated, completion: completion)
}
public override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
alertWindow = nil
}
}
另外贴出popover的用法
在想用于popover的UIViewController的初始化加上如下代码
required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
self.modalPresentationStyle = .popover;
self.preferredContentSize = CGSize(width: 280, height: 265);
self.popoverPresentationController?.delegate = self
}
let controller = UIStoryboard(name: "DateSelector", bundle: Bundle(for: DateSelectorVC.self)).instantiateViewController(withIdentifier: "dateSelector") as? DateSelectorVC
controller?.mViewModel.mType = type
controller?.mViewModel.mSelect = select
let popController = controller?.popoverPresentationController
popController?.sourceView = sender
popController?.sourceRect = sender.bounds
popController?.permittedArrowDirections = [.up, .down]
controller?.showVC(animated: true, completion: nil)