SwiftUI 中的全局警报

Posted

技术标签:

【中文标题】SwiftUI 中的全局警报【英文标题】:Global alert in SwiftUI 【发布时间】:2020-10-25 10:21:26 【问题描述】:

我正在尝试在 SwiftUI 中显示全局警报。无论当前在屏幕上显示/呈现什么(例如工作表),此警报都应显示在所有内容之上。

这是我的代码:

@main
struct MyApp: App 
    
    @State private var showAlert = false
    
    var body: some Scene 
        WindowGroup 
            MainView()
                .onReceive(NotificationCenter.default.publisher(for:NSNotification.Name.SomeNotification), perform:  _ in
                    showAlert = true
                )
                .alert(
                    isPresented: $showAlert,
                    content: Alert(title: Text("Alert!"))
                )
        
    

这在某些情况下不起作用,例如,如果在屏幕上当前显示工作表时收到通知。在这种情况下,不会显示警报,控制台上会显示以下消息:

块引用 [演示]尝试本上 TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier EM> _:0x7fbee642ac60>(来自 TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier EM> _:0x7fbee642ac60>),其已经呈现TtGC7SwiftUI22SheetHostingControllerVS_7AnyView: 0x7fbee8405360>.

这是有道理的,因为我试图在已经呈现工作表的视图上呈现警报。

在 UIKit 上,我使用以下类实现了这一点:

class GlobalAlertController: UIAlertController 
    
    var globalPresentationWindow: UIWindow?
    
    func presentGlobally(animated: Bool, completion: (() -> Void)?) 
        globalPresentationWindow = UIWindow(frame: UIScreen.main.bounds)
        globalPresentationWindow?.rootViewController = UIViewController()
        globalPresentationWindow?.windowLevel = UIWindow.Level.alert + 1
        globalPresentationWindow?.backgroundColor = .clear
        globalPresentationWindow?.makeKeyAndVisible()
        globalPresentationWindow?.rootViewController?.present(self, animated: animated, completion: completion)
    
    
    override func viewDidDisappear(_ animated: Bool) 
        super.viewDidDisappear(animated)
        globalPresentationWindow?.isHidden = true
        globalPresentationWindow = nil
    


此类允许我以这种方式在所有内容之上显示全局警报:

let alertController = GlobalAlertController(title: "Title", message: "Message", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Done", style: .cancel, handler: nil))
alertController.presentGlobally(animated: true, completion: nil)

有人知道如何在 SwiftUI 中实现类似的东西吗?

【问题讨论】:

下面解决了类似的问题***.com/a/63259094/12299030,应该会有所帮助。 【参考方案1】:

刚刚发现我实际上可以使用我的旧 UIKit 代码来实现这一点。唯一需要更改的是添加对场景的支持(SwiftUI 设计使用场景),如下所示:

class GlobalAlertController: UIAlertController 
    
    var globalPresentationWindow: UIWindow?
    
    func presentGlobally(animated: Bool, completion: (() -> Void)?) 
        globalPresentationWindow = UIWindow(frame: UIScreen.main.bounds)
        
        //This is needed when using scenes.
        if let currentWindowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene 
            globalPresentationWindow?.windowScene = currentWindowScene
        

        globalPresentationWindow?.rootViewController = UIViewController()
        globalPresentationWindow?.windowLevel = UIWindow.Level.alert + 1
        globalPresentationWindow?.backgroundColor = .clear
        globalPresentationWindow?.makeKeyAndVisible()
        globalPresentationWindow?.rootViewController?.present(self, animated: animated, completion: completion)
    
    
    override func viewDidDisappear(_ animated: Bool) 
        super.viewDidDisappear(animated)
        globalPresentationWindow?.isHidden = true
        globalPresentationWindow = nil
    


现在我可以像这样显示全局警报:

@main
struct MyApp: App 
    var body: some Scene 
        WindowGroup 
            MainView()
                .onReceive(NotificationCenter.default.publisher(for:NSNotification.Name.SomeNotification), perform:  _ in
                    let alertController = GlobalAlertController(title: "Title", message: "Message", preferredStyle: .alert)
                    alertController.addAction(UIAlertAction(title: "Done", style: .cancel, handler: nil))
                    alertController.presentGlobally(animated: true, completion: nil)
                )
        
    

它可以工作,虽然更类似于 SwiftUI 的方法会很好。

【讨论】:

以上是关于SwiftUI 中的全局警报的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 警报操作需要点击两次

在 SwiftUI 中创建警报时收到构建错误

SwiftUI:以编程方式关闭警报

如何使用 SwiftUI 呈现警报

SwiftUI:创建自定义警报

SwiftUI同一按钮的多个警报[重复]