Reputation: 85542
It appears that Window
is not available on visionOS, only WindowGroup
. If I want to have a window with only one instance (say, a Menu or similar), how can I ensure that each time I call openWindow
, the same window appears, and a new one is not created?
Upvotes: 4
Views: 1050
Reputation: 796
I have a rather quick and dirty solution that did the job for me. I had no other idea than just caching the windows ID's in some global Set
and check against that whenever opening a new window.
E.g. inside of your App
conforming struct:
@main
struct MyApp: App {
static var openendWindowsIDs: Set<String> = []
//...
}
Then wherever you open that new window you can check against that Set
(The following is just an example resulting in some boilerplate so you would probably abstract it away somehow)
Button {
let windowID = "myWindowsUniqueId"
if !MyApp.openendWindowsIDs.contains(windowID) {
openWindow(id: windowID)
}
MyApp.openendWindows.insert(windowID)
}
(Or even do not show this button or whatever triggers the window at all by checking before)
Also do not forget to remove the window's id somewhere it makes sense, e.g. in the main view of that window you are closing:
.onDisappear(perform: {
MyApp.openendWindows.remove("myWindowsUniqueId")
})
The documentation for WindowGroup
mentions:
If a window with a binding to the same value that you pass to the openWindow action already appears in the user interface, the system brings the existing window to the front rather than opening a new window. I still always got new instances. That is why I use the example above now.
Together with this code example:
WindowGroup(for: Message.ID.self) { $messageID in
MessageDetail(messageID: messageID)
}
How I understood this: If you call openWindow
with the same (here) messageID
passed, there should not be opened a new window. However, I did not get this to work.
Upvotes: 1
Reputation: 9277
I suspect this may be intentional to allow users to 'find' windows they've misplaced. It looks like it will be easy to lose things in the environment and perhaps it will make sense from a UX perspective to allow the user to have multiple sets of controls around their environment.
If you want to control only opening one instance of a WindowGroup, then dismissing it first, before opening is a reasonable way, as that will bring it back to where the user is looking.
@Environment(\.openWindow) private var openWindow
@Environment(\.dismissWindow) private var dismissWindow
Button("open") {
dismissWindow(id: "targetView")
openWindow(id: "targetView")
}
Otherwise keeping track of the window lifecycle using the scene phase, combined with .onDisappear
to track when a view is dismissed is more involved but also works. controlActiveState
would be the preferred method, but that seems unavailable on visionOS (for now).
Upvotes: 1