【问题标题】:SwiftUI & macOS : How to detect last window being closed and show alert that app will quitSwiftUI 和 macOS:如何检测关闭的最后一个窗口并显示应用程序将退出的警报
【发布时间】: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/… 选择合适的。
  • 我用错了“人”?你可以再详细一点吗?如上代码所示,我实现了应用委托。
  • 赞成。我也有同样的问题。

标签: macos swiftui appdelegate


【解决方案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 })
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多