如何检测窗口关闭?

问题描述 投票:0回答:4

目标:

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

我的尝试:

当用户关闭 macOS 应用程序窗口时,

onDisappear
似乎不会被调用

问题:

  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")
        }
    }
}
macos swiftui
4个回答
7
投票

对于执行此操作的“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
                }
            }
    }
}

5
投票

如果有人觉得这很有趣,我已经以不同的(可能更好)的方式解决了这个问题。

@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 { }
    }
}

根据 Apple 文档,

task(priority:_:)
修饰符创建一个与视图生命周期匹配的任务,并在视图被丢弃时取消。我们可以创建一个无限的
AsyncStream
(空但从未完成)来等待任务被取消(因此在上面的示例中窗口被关闭),然后执行所需的操作。

我认为这是 SwiftUI 中唯一正确记录的情况,我们确实可以检测到窗口何时关闭。


3
投票

您可以使用

NSWindow.willCloseNotification
通知:

struct ContentView: View {
    
    var body: some View {
        
        Text("xyz")
            .onReceive(NotificationCenter.default.publisher(for: NSWindow.willCloseNotification)) { newValue in
                print("close")
            }
    }
}

1
投票

在 Swift

5.10
Xcode
15.3
onDismiss
似乎工作正常,我猜这只是实现上的一个错误。

关闭

Window(手动或编程)时调用

onDismiss

示例:

WindowGroup {
    ContentView()
        .onDisappear {
            // window was closed
        }
}
© www.soinside.com 2019 - 2024. All rights reserved.