The reason is on HWS+ Introduction to Observation but will try to give you quotes
Right now @Environment does not have a projected value, which means we can’t use the $ prefix to access bindings to its data. This is what’s causing our problem: we’re trying to bind our text fields to something that doesn’t actually provide bindings any more, which isn’t possible.
This is Very Annoying, and I hope it will change before iOS 17 is released as final. During the WWDC23 digital lounges, one of the SwiftUI team specifically said, “for this to work we need an API that adds a projected value to @Environment – if that's something you'd like to see, please file a feedback report!” So, this is your chance: if you want this behavior to change, please tell Apple that you’d like them to add support for creating bindings from @Observable objects in the environment.
In the meantime – and if you’re watching this later, if Apple have yet to change this behavior – we need a fix, and like many SwiftUI fixes this is another property wrapper. Yes, just as Apple has removed @EnvironmentObject, @StateObject, and @ObservedObject, they have introduced another new one, this time called @Bindable.
So the main should be this. As you should put into environment at start of app.
@main
struct TestApp: App {
@State var menuState = SportMenuStatus()
var body: some Scene {
WindowGroup {
ContentView()
.environment(menuState)
}
}
}
ContentView
struct ContentView: View {
var body: some View {
VStack {
HomeView()
}
.padding()
}
}
HomeView
struct HomeView: View {
@Environment(SportMenuStatus.self) var menuState
var body: some View {
@Bindable var menuState = menuState
Button {
menuState.isSportMenuShowing = true
} label: {
Text("Show Sheet \(menuState.isSportMenuShowing)")
}
.sheet(isPresented: $menuState.isSportMenuShowing) {
Text("Sheet Presented")
}
}
}
or ContentView
struct ContentView: View {
@Environment(SportMenuStatus.self) var menuState
var body: some View {
VStack {
HomeView(menuState: menuState)
}
.padding()
}
}
and HomeView
struct HomeView: View {
@Bindable var menuState: SportMenuStatus
var body: some View {
Button {
menuState.isSportMenuShowing = true
} label: {
Text("Show Sheet")
}
.sheet(isPresented: $menuState.isSportMenuShowing) {
Text("Sheet Presented")
}
}
}