In the following, reproduced example, I have the following code which makes up a single screen. There's a lot of code, but it's simple!
The intended function: The screen is filled with a plain color. Below the color, there is a picker (DisclosureGroup
in this example, but I don't think it matters which type of picker is used.), and this picker lets the user switch between mode1
and mode2
. The screen starts off being filled black, and once the user picks a mode, the black view should change to red using didSet
on the mode
variable.
The issue is mainly with the didSet
of the mode
variable. I know the mode
is being updated, because the label (commented "shows current mode") is changing. However, the color of the view itself isn't updating, as defined in the didSet
I checked here, and I have an @State, but the issue persists.
I get no errors, and am running XCode 13.2
Code:
struct ContentView: View {
@State var color: Color = .black //COLOR BEING SHOWN
@State var mode: SHModes = .mode1 { //CURRENT MODE
didSet {
color = .red
}
}
public enum SHModes { //MODE OPTIONS
case mode1, mode2
}
var body: some View {
VStack {
color
ModePicker(mode: $mode)
}
}
struct ModePicker: View {
@Binding var mode: SHModes //BINDING TO CONTENTVIEW MODE
@State var clicked = false //the rest is irrelevant code , just changes the binding variable above
var body: some View {
DisclosureGroup(isExpanded: $clicked, content: {
VStack {
if mode != .mode1 {
Text("Mode 1")
.onTapGesture {
mode = .mode1
clicked.toggle()
}
}
if mode != .mode2 {
Text("Mode 2")
.onTapGesture {
mode = .mode2
clicked.toggle()
}
}
}
}, label: {
Text(mode == .mode1 ? "mode1" : "mode2") //label for current mode, proves `mode` is being changed
})
}
}
}
I suspect it has to do with the way I'm binding the mode
value, but why isn't the color on the view updating when didSet
is called?
Use instead .onChange(of:...
, like
var body: some View {
VStack {
color
ModePicker(mode: $mode)
.onChange(of: mode) { _ in // or with arg if needed
color = .red // << here
}
}
}