Reputation: 994
I'm opening an immersive space:
Button {
Task{
await openImmersiveSpace(id: "globe")
}
} label: {
Text("Jump to Globe")
}
If I click multiple times I get a warning: Unable to present another Immersive Space when one is already requested or connected
The solution I can think of at present is to create an environment variable to save the state of entering the immersive space, and determine whether it has been entered when the button is clicked.
Globe()
.onAppear{
model.isShowGlobe = true
}
.onDisappear{
model.isShowGlobe = false
}
Button {
if model.isShowGlobe{
return
}
Task{
await openImmersiveSpace(id: "globe")
}
} label: {
Text("Jump to Globe")
}
Or after I enter the immersive space from the Globe
, hide or close the Globe
. Do you have any better suggestions?
Upvotes: 1
Views: 2006
Reputation: 58113
At first, I should say that a visionOS app can display just ONE space at a time. You'll get an error if you try to open a new space while the previous one is visible. To dismiss an open space, use the code below. There's no need to specify an id when dismissing your immersive space because there can only be just one space open at a time.
import SwiftUI
struct DismissImmersiveness : View {
@Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace
var body: some View {
Button("Close Immersive Space") {
Task {
await dismissImmersiveSpace()
}
}
}
}
However, the most robust approach in your case is to have just one button, switching it from the True
state to the False
state. This is what it looks like:
import SwiftUI
import RealityKit
struct ContentView: View {
@Environment(\.openImmersiveSpace) var openImmersiveSpace
@Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace
@State var isPressed = false
@State var immersiveSpaceIsVisible = false
var body: some View {
VStack {
RealityView { content in /* RealityKit scene */ }
Button(isPressed ? "Space Opened" : "Space Closed") {
isPressed.toggle()
}.foregroundColor(isPressed ? .green : .red)
}
.onChange(of: isPressed) { (_, new) in
Task {
if new {
switch await openImmersiveSpace(id: "ImmersiveSpace") {
case .opened: immersiveSpaceIsVisible = true
case .error: fallthrough
case .userCancelled: fallthrough
@unknown default: immersiveSpaceIsVisible = false
}
} else if immersiveSpaceIsVisible {
await dismissImmersiveSpace()
immersiveSpaceIsVisible = false
}
}
}
}
}
P. S.
Also, the Unable to present another Immersive Space when one is already requested or connected
error appears in cases where you simultaneously call Immersion Space from the ContentView and from the App files.
Upvotes: 2