iOS13.0版本以上新建UIWindow显示UIAlertController遇到的问题以及解决方式

在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)
0 0 vote
Article Rating
Subscribe
提醒
guest
0 评论
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x