You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI/VisionOS中如何从子窗口向父窗口实现回调?

解决SwiftUI多窗口间回调的实现方案

方案一:基于ObservableObject的共享状态(推荐复杂场景)

通过一个可观察对象作为状态中间层,让主窗口和新窗口共享状态,新窗口修改状态后,主窗口监听状态变化来执行回调逻辑。

1. 定义共享状态类

import SwiftUI

class AppState: ObservableObject {
    // 标记是否触发回调
    @Published var triggerCallback = false
    
    // 重置标记,避免重复触发
    func resetFlag() {
        triggerCallback = false
    }
}

2. 在App中注入共享状态

@main
struct DemoApp: App {
    @StateObject private var appState = AppState()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(appState)
        }

        Window("test", id: Test.self) { $test in
            TestView(test: test)
                .environmentObject(appState)
        }
    }
}

3. 修改ContentView监听状态

struct ContentView: View {
    @Environment(.openWindow) private var openWindow
    @EnvironmentObject private var appState: AppState
    
    var body: some View {
        Button {
            openWindow(id: "test", for: Test(name: "Window"))
            appState.resetFlag()
        } label: {
            Text("open text")
        }
        .onChange(of: appState.triggerCallback) { newValue in
            if newValue {
                // 这里写收到回调后的处理逻辑
                print("TestView触发了回调")
                appState.resetFlag()
            }
        }
    }
}

4. 修改TestView触发状态变化

struct TestView: View {
    let test: Test
    @Environment(.dismiss) var dismiss
    @EnvironmentObject private var appState: AppState
    
    var body: some View {
        Button {
            appState.triggerCallback = true
            dismiss()
        } label: {
            Text("RECHECK")
        }
    }
}

5. 调整Test结构体(需遵循Identifiable)

struct Test: Identifiable {
    let id = UUID()
    let name: String
}

方案二:基于闭包的绑定传递(适用于简单场景)

通过给数据模型添加闭包属性,结合Binding传递,让新窗口直接调用主窗口传入的闭包。

1. 修改Test结构体添加闭包

struct Test: Identifiable {
    let id = UUID()
    let name: String
    var callback: (() -> Void)?
}

2. 修改ContentView传递闭包

struct ContentView: View {
    @Environment(.openWindow) private var openWindow
    
    var body: some View {
        Button {
            var test = Test(name: "Window")
            test.callback = {
                // 这里写回调逻辑
                print("收到TestView的回调")
            }
            openWindow(id: "test", for: test)
        } label: {
            Text("open text")
        }
    }
}

3. 修改TestView调用闭包

struct TestView: View {
    @Binding var test: Test
    @Environment(.dismiss) var dismiss
    
    var body: some View {
        Button {
            test.callback?()
            dismiss()
        } label: {
            Text("RECHECK")
        }
    }
}

4. 调整App中的Window绑定

@main
struct DemoApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }

        Window("test", id: Test.self) { $test in
            TestView(test: $test)
        }
    }
}

内容的提问来源于stack exchange,提问作者NigelGe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 23:45:03