SwiftUI 和 macOS:如何检测关闭的最后一个窗口并显示应用程序将退出的警报

Posted

技术标签:

【中文标题】SwiftUI 和 macOS:如何检测关闭的最后一个窗口并显示应用程序将退出的警报【英文标题】:SwiftUI & macOS : How to detect last window being closed and show alert that app will quit 【发布时间】:2021-08-25 17:56:47 【问题描述】:

我正在创建一个 SwiftUI 应用程序。在用户关闭最后一个窗口时,我想提示用户并通知他们应用程序也将退出。

我查看了在应用程序退出时创建警报的两种解决方案here,还查看了在最后一个窗口关闭时关闭应用程序的解决方案here。

然而,我已经开始工作了,但没有一起工作。我正在寻找一种方法来检测用户何时关闭应用程序中的最后一个窗口,然后通过警报提示用户,让他们知道它将退出应用程序并询问他们是要继续还是取消。

使用.onDisappear 似乎不起作用。我已经实现了一个appDelegate,它是applicationShouldTerminateAfterLastWindowClosed 方法,但是当最后一个窗口关闭时,它似乎没有在我的应用程序中提示.alert 行为。

Application

class Application: NSObject, NSApplicationDelegate, ObservableObject 
    
    @Published var willTerminate = false
    
    override init() 
        super.init()
    
    
    func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply 
        if NSApplication.shared.windows.count == 0 
            return .terminateNow
        
        self.willTerminate = true
        return .terminateLater
    
    
    func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool 
        return true
    
    
    func resume() 
        NSApplication.shared.reply(toApplicationShouldTerminate: false)
    
    
    func close() 
        NSApplication.shared.reply(toApplicationShouldTerminate: true)
    


struct WindowAccessor: NSViewRepresentable 
    
    @Binding var window: NSWindow?
    
    func makeNSView(context: Context) -> NSView 
        let view = NSView()
        DispatchQueue.main.async 
            self.window = view.window
        
        return view
    
    
    func updateNSView(_ nsView: NSView, context: Context) 

ContentView

struct ContentView: View 
    @State private var window: NSWindow?
    @EnvironmentObject private var appDelegate: Application
     var body: some View 
        ZStack 
            MyView()
            // ...
            .onDisappear(
                // Code in here does not run when WindowAccessor is set to background
                )
                .background(WindowAccessor(window: self.$window))
                .alert(isPresented: Binding<Bool>(get:  self.appDelegate.willTerminate && self.window?.isKeyWindow ?? false , set:  self.appDelegate.willTerminate = $0 ), content: 
                    SoloLogger(for: .window).coreLog(message: "ApplicationClosedEvent", level: .info)
                    return Alert(title: Text("Quit Application?"),
                          message: Text("Do you really want to quit the application?"),
                          primaryButton: .default(Text("Cancel"), action: self.appDelegate.resume() ),
                          secondaryButton: .destructive(Text("Quit"), action: self.appDelegate.close()))
                )
        
    

【问题讨论】:

你找错人了。在developer.apple.com/documentation/appkit/… 选择合适的。 我用错了“人”?你可以再详细一点吗?如上代码所示,我实现了应用委托。 赞成。我也有同样的问题。 【参考方案1】:

我一直在做类似的事情。

您可以从环境中获取@AppDelegate,无需创建WindowAccessor。

我创建了一个可以添加到内容视图的 ZStack 中的视图:

struct MacOSQuitCheckView: View 
    
    // MARK: - PROPERTIES
    @EnvironmentObject private var appDelegate: AppDelegate
    
    // MARK: - VIEW BODY
    var body: some View 
        EmptyView()
            .alert("App wants to quit?"), isPresented: isPresented) 
                Button("Do not quit", role: .cancel, action: appDelegate.resume)
                Button("Quit", action: appDelegate.close)
            
    
    
    // MARK: - PRIVATE COMPUTED PROPERTIES
    private var isPresented: Binding<Bool> 
        Binding<Bool>(get:  self.appDelegate.willTerminate , set:  self.appDelegate.willTerminate = $0 )
    

【讨论】:

以上是关于SwiftUI 和 macOS:如何检测关闭的最后一个窗口并显示应用程序将退出的警报的主要内容,如果未能解决你的问题,请参考以下文章

如何在 macOS 上检测 SwiftUI 中的键盘事件?

(SwiftUI, MacOS 11.0) 如何在 SecureTextFeild 中检测焦点?

如何检测何时点击 TextField? (MacOS 上的 SwiftUI)

如何在 SwiftUI 生命周期中删除 macOS 中的最大化、最小化和关闭按钮?

如何检测手表操作系统是不是关闭了 ios 应用程序 SWIFTUI

SwiftUI 2 - 如何防止顶部部分在 macOS 和 iPadOS 的列表中关闭