SwiftUI macOS 检测窗口关闭

5

目标:

  • 我有一个使用Window场景的SwiftUI应用程序
  • 当用户关闭红色窗口时,我想调用f1()

我的尝试:

onDisappear在用户关闭macOS应用程序窗口时似乎不会被调用

问题:

  1. 在macOS(SwiftUI)中,如何检测用户关闭窗口?
  2. 我是否遗漏了什么?

代码

应用程序

@main
struct DemoApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        
        Window("test", id: "test") {
            Color.red
                .onDisappear {
                    print("onDisappear")
                    f1()
                }
        }
    }
    
    func f1() {
        print("f1 called")
    }
}

内容视图

struct ContentView: View {
    @Environment(\.openWindow) private var openWindow
    var body: some View {
        Button("show red") {
            openWindow(id: "test")
        }
    }
}
3个回答

5

若要以“SwiftUI方式”实现此操作,请查看环境属性controlActiveState。当窗口失去焦点或关闭窗口时,该值将设置为.inactive

struct ContentView: View {
    @Environment(\.controlActiveState) private var controlActiveState

    var body: some View {
        Text("Hello, World!")
            .onChange(of: controlActiveState) { newValue in
                switch newValue {
                case .key, .active:
                    break
                case .inactive:
                    // Do your stuff.
                @unknown default:
                    break
                }
            }
    }
}

1
哇!!!正是我想要的,非常感谢!!! - user1046037
“Inactive”并不意味着窗口已关闭……所以问题仍未得到解答,如何区分“关闭”和“不活动”? - undefined

1
你可以使用 NSWindow.willCloseNotification 通知:
struct ContentView: View {
    
    var body: some View {
        
        Text("xyz")
            .onReceive(NotificationCenter.default.publisher(for: NSWindow.willCloseNotification)) { newValue in
                print("close")
            }
    }
}

非常感谢,我只是在想是否有SwiftUI的方法可以做到这一点?我尝试过scenePhaseisFocused,但找不到方法。 - user1046037

1
如果有人觉得这个有趣的话,我用一种不同(可能更好)的方式来解决这个问题。
@main
struct DemoApp: App {
    var body: some Scene {
        Window("test", id: "test") {
            Color.red
                .task {
                    // perform action when window is opened
                    await Task.waitTillCancel()
                    // perform action after window is closed
                }
        }
    }
}

extension Task where Success == Void, Failure == Never {
    static func waitTillCancel() async {
        let asyncStream = AsyncStream<Int> { _ in }
        for await _ in asyncStream { }
    }
}

根据苹果文档,.task修饰符创建一个与视图生命周期相匹配的任务,并在视图被丢弃时取消。我们可以创建一个无限的AsyncStream(空但永远不会结束),以等待任务被取消(因此在上面的示例中窗口关闭),然后执行所需的操作。
我认为这是SwiftUI中唯一被正确记录的情况,我们可以确定地检测到窗口何时关闭。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接