【问题标题】:Every UIAlertController disappear automatically before user responds - since iOS 13在用户响应之前,每个 UIAlertController 都会自动消失 - 从 iOS 13 开始
【发布时间】:2019-09-27 09:44:34
【问题描述】:

由于我使用的是 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 甚至 iOS 13.1 之后,它变得一团糟...... :(

  • 您知道是什么原因造成的吗?

  • 以及如何防止将 UIAlert 用作潜意识消息:)?

【问题讨论】:

  • 但是以这种方式制作第二个窗口总是错误的;现在框架已经赶上你了。

标签: swift uialertcontroller ios13


【解决方案1】:

我遇到了完全相同的问题,并通过将显示警报的窗口保持在强变量中来解决它。

例如,您可以在 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

【讨论】:

  • 当您的应用支持 iOS 13 中的场景时,这将无法正常工作。
  • 哇侯,太棒了!它运作良好。但是一旦关闭,我的按钮、文本字段、标签栏或导航栏都不再启用......你也有这个问题吗?
  • @Creanomy 您需要确保在关闭警报视图时将窗口从视图中删除。我稍后会用我的做法来编辑我的答案。
  • @user_Dennis_Mostajo 您是否遇到问题中描述的相同问题?警报出现一瞬间然后消失?这将在窗口级别为 (alert)+1 的窗口上显示警报,这可能是应用程序中最顶层的窗口。
  • @user_Dennis_Mostajo 您确定您在安全的地方持有对警报窗口的强引用吗?在您发布的链接中,您正在 showAlertGlobally func 中创建它。
【解决方案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,我猜有时你找不到主窗口。当它不起作用时检查视图控制器层次结构。
【解决方案3】:

基于pepsyanswer。 如果你不想关心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)
    }
}

【讨论】:

    【解决方案4】:

    在您考虑将alertController 制作成window 之前,请检查您的动画或其他UI 事物是否一起动画。

    例如,如果你同时使用self.dismiss(VC)self.present(alertController),就会出现问题

    最好的开发方式不是忽略不规则的ui事件,而是先检查其他有问题的东西。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-04
      • 1970-01-01
      • 1970-01-01
      • 2015-09-12
      • 2020-06-27
      • 1970-01-01
      相关资源
      最近更新 更多