自iOS 13以来,每个UIAlertController在用户响应之前都会自动消失。

11

自从我使用iOS 13后,每个 UIAlertController 在任何用户操作之前都会出现约半秒钟,然后立即消失。有什么想法吗?

由于我在应用程序的不同部分使用 UIAlertController,因此我使用了一个扩展,允许我从经典视图和collectionView(单元格、标题等)弹出。

public extension UIAlertController {
    func show() {
        let win = UIWindow(frame: UIScreen.main.bounds)
        let vc = UIViewController()
        vc.view.backgroundColor = .clear
        vc.view.tintColor = Theme.mainAccentColor
        win.rootViewController = vc
        win.windowLevel = UIWindow.Level.alert + 1
        win.makeKeyAndVisible()
        vc.present(self, animated: true, completion: nil)
    }
}

这里是使用此扩展的示例:

fileprivate func showMissingAlert() {
        let alert = UIAlertController(title: "blablabla", message: "blablablablabla blabla", preferredStyle: UIAlertController.Style.alert)
        alert.show()
        alert.view.tintColor = Theme.mainAccentColor
        let cancelAction = UIAlertAction(title: "OK, blabla", style: .default, handler: {(alert: UIAlertAction!) in print("ok, leave")})
        alert.addAction(cancelAction)
    }

并且在我的代码中:

showMissingAlert()

iOS 13之前,每个UIAlert都能正常使用...自从我升级到iOS 13甚至是13.1以后,它变成了一团糟... :(

  • 有什么想法可以解决这个问题吗?

  • 如何避免使用UIAlert作为潜意识传递的信息 :) ?


  • 有什么想法可以解决这个问题吗?

  • 如何避免将UIAlert用作潜意识信息的传递?:)


但是以这种方式创建第二个窗口一直是错误的;现在框架已经跟上了你的步伐。 - matt
4个回答

12

我遇到了完全相同的问题,通过将包含警告的窗口保存在一个强引用变量中来解决它。

例如,您可以在AppDelegate中保存一个用于提示警告的窗口,并在您的UIAlertController扩展中使用它。

//In app delegate
let alertWindow: UIWindow = {
    let win = UIWindow(frame: UIScreen.main.bounds)
    win.windowLevel = UIWindow.Level.alert + 1
    return win
}()

然后,在你的扩展程序中:

public extension UIAlertController {
    func show() {
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let vc = UIViewController()
        vc.view.backgroundColor = .clear
        vc.view.tintColor = Theme.mainAccentColor
        appDelegate.alertWindow.rootViewController = vc
        appDelegate.alertWindow.makeKeyAndVisible()
        vc.present(self, animated: true, completion: nil)
    }
}
您还需要确保在关闭警报时将警报窗口从视图中移除,否则您的应用程序将变得无响应,因为所有的点击都将被(不可见的)警报窗口处理,而该窗口仍在最上方。 我通过将以下代码添加到警报中的所有操作的处理程序来实现此功能:
(UIApplication.shared.delegate as! AppDelegate).alertWindow.isHidden = true

1
当你的应用程序支持iOS 13中的场景时,这种方法不会很好地工作。 - rmaddy
哇,太棒了!它运行得很好。 但是一旦关闭,我的所有按钮、文本框、选项卡栏或导航栏都无法使用了...你也遇到过这个问题吗? - Creanomy
@pepsy,我在 Obj-C 也遇到了同样的问题(https://dev59.com/Jbbna4cB1Zd3GeqPdpoO)。你有解决方法吗?感谢您的时间。 - Reanimation
1
@user_Dennis_Mostajo,您是否遇到了问题描述中提到的同样的问题?警报只会出现一瞬间就消失了吗?这将在具有(alert)+1窗口级别的窗口上显示警报,这可能是您应用程序中最顶层的窗口。 - pepsy
2
@user_Dennis_Mostajo 你确定你在一个安全的地方持有了对警报窗口的强引用吗?在你发布的链接中,你是在showAlertGlobally函数内创建它的。 - pepsy
显示剩余9条评论

2
你也可以尝试这个解决方案。它对我有效。
在你的类中写下以下方法。
func presentViewController(alertController: UIAlertController, completion: (() -> Void)? = nil) {
        if var topController = UIApplication.shared.keyWindow?.rootViewController {
            while let presentedViewController = topController.presentedViewController {
                topController = presentedViewController
            }

            DispatchQueue.main.async {
                topController.present(alertController, animated: true, completion: completion)
            }
        }
    }

然后在您的代码中按照以下方式调用它
let alertController = UIAlertController(title: "Discard Photo?",
                                                message: "Your photo will not be attached",
                                                preferredStyle: .alert)
        alertController.addAction(UIAlertAction(title: "Keep Photo", style: .default, handler: nil))
        alertController.addAction(UIAlertAction(title: "Discard", style: .default) { (_) -> Void in
            self.PhotoStack.deletePhoto(at: index)
            self.cameraBtn.isEnabled = true
        })

        self.presentViewController(alertController: alertController)

@Skywalker,我的猜测是有时候你找不到主窗口。当它无法正常工作时,请检查视图控制器层次结构。 - Chathura Palihakkara

1
基于pepsy answer。 如果您不想关心alertWindow.isHidden = true stuff,您可以这样做:
class AlertHandler {
    private static let alertWindow: UIWindow = {
        let window = UIWindow(frame: UIScreen.main.bounds)
        window.windowLevel = UIWindow.Level.alert + 1
        return window
    }()

    private var alertController: UIAlertController

    init(title: String?,
         message: String?) {
        alertController = UIAlertController(title: title,
                                            message: message,
                                            preferredStyle: .alert)
    }

    func addAction(title: String?,
                   style: UIAlertAction.Style,
                   handler: ((UIAlertAction) -> Void)? = nil) {
        let action = UIAlertAction(title: title,
                                   style: style) { action in
                                    handler?(action)
                                    AlertHandler.alertWindow.isHidden = true
        }
        alertController.addAction(action)
    }

    func present() {
        AlertHandler.alertWindow.rootViewController = UIViewController()
        AlertHandler.alertWindow.makeKeyAndVisible()
        AlertHandler.alertWindow.rootViewController?.present(alertController,
                                                             animated: true,
                                                             completion: nil)
    }
}

1
在考虑将alertController放入window之前,请检查您的动画或其他UI元素是否同时进行动画。
例如,如果您同时执行self.dismiss(VC)self.present(alertController),会出现问题。
最好的开发方式不是忽略不规则的UI事件,而是首先检查是否存在其他有问题的事情。

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