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
相关产品推荐
相关产品推荐

