I've created some SwiftUI code that use an EnvironmentObject
to store boolean values for popping back to the root view and another EnvironmentObject
to store a score variable that is intended to be used across multiple views.
In this example, I have two games, a Red Game and a Blue Game. I have booleans (.redStacked
and .blueStacked
) that are initially set to false
. Their respective NavigationLinks
set them to true
. At the end of the game, a "Home" button sets it back to false
, and this unwinds the navigation stack back to the root view.
The problem that I am running into is that any update to the score EnvironmentObject
unexpectedly and prematurely pops the navigation stack back to the root view.
In the following example code, the only difference between games is that the Red Game button adds +1 to its score environmental variable. In this instance, the one point is added and the navigation link to the final page is executed, but then it immediately rubberbands back to the start. The Blue Game does not update the score environmental variable and transitions as expected.
I welcome any insights on why this occurs. Thanks in advance.
import SwiftUI
class Pop: ObservableObject {
@Published var redStack = false
@Published var blueStack = false
}
class Score: ObservableObject {
@Published var redTotal = 0
@Published var blueTotal = 0
}
struct GameSelection: View {
@ObservedObject var pop = Pop()
@ObservedObject var score = Score()
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: RedStart(), isActive: $pop.redStack) {
Text("Play Red Game") //Tapping this link sets redStacked to true
}.foregroundColor(.red)
Divider()
NavigationLink(destination: BlueStart(), isActive: $pop.blueStack) {
Text("Play Blue Game") //Tapping this link sets blueSteacked to true
}.foregroundColor(.blue)
}
}
.environmentObject(score)
.environmentObject(pop)
}
}
struct RedStart: View {
@State var goToNextView : Bool = false
@EnvironmentObject var score : Score
var body: some View {
VStack {
NavigationLink(destination: RedEnd(), isActive: $goToNextView) {}
Button(action: {
score.redTotal += 1
goToNextView = true
}, label: {
Text("Add 1 Point. Move to Next Screen")
.foregroundColor(.red)
})
}
}
}
struct BlueStart: View {
@State var goToNextView : Bool = false
@EnvironmentObject var score : Score
var body: some View {
VStack {
NavigationLink(destination: BlueEnd(), isActive: $goToNextView) {}
Button(action: {
// score.blueTotal += 1
goToNextView = true
}, label: {
Text("Do NOT add points. Move to Next Screen")
.foregroundColor(.blue)
})
}
}
}
struct RedEnd: View {
@EnvironmentObject var pop: Pop
@EnvironmentObject var score: Score
var body: some View {
Button(action: {
pop.redStack = false
}, label: {
VStack {
Text("Your Score: \(score.redTotal)")
Text("Game Over")
Image(systemName: "house.fill")
}
.foregroundColor(.red)
})
}
}
struct BlueEnd: View {
@EnvironmentObject var pop: Pop
@EnvironmentObject var score: Score
var body: some View {
Button(action: {
pop.blueStack = false
}, label: {
VStack {
Text("Your Score: \(score.blueTotal)")
Text("Game Over")
Image(systemName: "house.fill")
}.foregroundColor(.blue)
})
}
}
struct GameSelection_Previews: PreviewProvider {
static var previews: some View {
GameSelection()
}
}