Below I have the code for my picker:
struct pickerSwitch: View {
@ObservedObject var appState: AppState
@State var selection: String = "Red"
var colors = ["Red", "Blue"]
init(appState: AppState) {
print("Init ran again")
self.appState = appState
if appState.showBlueControl {
UISegmentedControl.appearance().setTitleTextAttributes([.font : UIFont.preferredFont(forTextStyle: .headline)], for: .normal)
UISegmentedControl.appearance().backgroundColor = .blue
} else {
UISegmentedControl.appearance().setTitleTextAttributes([.font : UIFont.preferredFont(forTextStyle: .headline)], for: .normal)
UISegmentedControl.appearance().backgroundColor = .red
}
}
var body: some View {
Picker(selection: $selection, label: Text("")) {
ForEach(colors, id: .self) {
Text($0)
}
}.pickerStyle(SegmentedPickerStyle())
}
}
Elsewhere in my code, I have a button that changes the value of ‘showBlueControl’ for the specific instance of ‘AppState.’ In my Xcode logs, I see lots of the ‘Init ran again’ log so I thought the segmented control should be changing but for some reason the change only takes places when I close the view entirely and reopen it. How can I dynamically change the SegmentedControl when there is a SwiftUI state change (w/o closing/reopening the view)?
2
Answers
You just need an
@State
to keep track of the background color. Then you set the.background()
on the picker. To change your state variable, simply use.onChange
.You could use SwiftUI-Introspect. I prefer this rather than changing the
.id(_:)
of the view, because:When you change the ID of a view, you are causing it to be invalidated and then therefore recreated. It can also lead to some strange bugs such as the animation stopping weirdly, and inability to change tab mid-way through to interrupt the animation. However, with Introspect, the view doesn’t get reinitialized. The view body just gets updated when
appState
changes.Also, with Introspect the styling only affects just this one
Picker
– not every-single-one throughout the whole app.I also simplified how you deal with keeping track of the colors. Note that we bind to the selected color with
$appState.switchColor
.Code: