首页 > 解决方案 > 如何处理内置的 AlertController / 电子邮件提示出现在我的视图后面

问题描述

我的应用程序包含一个可以从任何地方呈现的模态 UIView。这是如何工作的,该present方法将视图作为子视图附加到关键窗口上:

func present(_ completion: ((Bool) -> ())? = { _ in }) {

    guard !isPresented else {
        return
    }

    if !isBackgroundReady {
        initializeBackground()
    }

    UIApplication.shared.keyWindow?.addSubview(backgroundView)
    UIApplication.shared.keyWindow?.addSubview(self)

    UIView.animate(withDuration: 0.3, animations: {
        self.backgroundView.alpha = 0.35
        self.alpha = 1.0
    }, completion: { _ in
        self.isPresented = true
        completion?(true)
    })
}

private func initializeBackground() {
    backgroundView.backgroundColor = UIColor.black
    backgroundView.alpha = 0.0
    backgroundView.frame = CGRect(x: UIScreen.main.bounds.midX, y: UIScreen.main.bounds.midY, width: UIScreen.main.bounds.width * 1.2, height: UIScreen.main.bounds.height * 1.2)
    backgroundView.center = CGPoint(x: UIScreen.main.bounds.midX, y: UIScreen.main.bounds.midY)
}

此模式包含一个电子邮件链接,用户可以单击该链接以打开电子邮件提示(如果长按,则为电子邮件操作表)。此链接是通过使用UITextView 上的 anNSAttributedString及其属性添加的:.link

let supportString = NSMutableAttributedString(
    string: "general.supportEmail".localized(),
    attributes: [
        .link: "mailto:\("general.supportEmail".localized())",
    ]
)
supportTextView.attributedText = supportString

但是,当电子邮件提示或操作表出现时,它会显示在模态视图的后面:

应用程序

是否有可能以我呈现模态的当前方式让提示/操作表出现在模态视图上方,或者我是否需要在某处添加某种识别器来检测这些视图之一何时出现并暂时关闭模态直到我的应用程序视图重新成为焦点?如果是后者,我将如何做到这一点?

标签: swiftmodal-dialoguialertcontroller

解决方案


关于为什么会发生这种情况的快速答案是,您在 Window 顶部呈现自定义模态视图,该视图将位于所有内容之上,并且您UIAlertController将在UIViewController呈现它时呈现(位于自定义视图下方)。

一种快速的解决方案是始终将您的自定义视图添加为当前“顶部”的子视图UIViewController。您可以通过UIViewController扩展来做到这一点 - 像这样:

extension UIViewController {

    static func topViewController(_ viewController: UIViewController? = nil) -> UIViewController? {
        let viewController = viewController ?? UIApplication.shared.keyWindow?.rootViewController
        if let navigationController = viewController as? UINavigationController, !navigationController.viewControllers.isEmpty {
            return self.topViewController(navigationController.viewControllers.last)
        } else if let tabBarController = viewController as? UITabBarController,
            let selectedController = tabBarController.selectedViewController
        {
            return self.topViewController(selectedController)
        } else if let presentedController = viewController?.presentedViewController {
            return self.topViewController(presentedController)
        }
        return viewController
    }

}

此扩展将处理任何UIViewController“在顶部”的内容,无论是在 a UINavigationController、 aUITabBarController还是仅以模态方式呈现等。应该涵盖所有情况。

之后,您可以调整您的present方法以考虑到这一点:

func present(_ completion: ((Bool) -> ())? = { _ in }) {
    guard !isPresented else {
        return
    }
    if !isBackgroundReady {
        initializeBackground()
    }
    guard let topViewController = UIViewController.topViewController() else { return }
    topViewController.view.addSubview(backgroundView)
    topViewController.view.addSubview(self)
    UIView.animate(withDuration: 0.3, animations: {
        self.backgroundView.alpha = 0.35
        self.alpha = 1.0
    }, completion: { _ in
        self.isPresented = true
        completion?(true)
    })
}

推荐阅读