In my SwiftUI view I have to trigger an action when a Toggle() changes its state. The toggle itself only takes a Binding. I therefore tried to trigger the action in the didSet of the @State variable. But the didSet never gets called.
Is there any (other) way to trigger an action? Or any way to observe the value change of a @State variable?
My code looks like this:
struct PWSDetailView : View {
@ObjectBinding var station: PWS
@State var isDisplayed: Bool = false {
didSet {
if isDisplayed != station.isDisplayed {
PWSStore.shared.toggleIsDisplayed(station)
}
}
}
var body: some View {
VStack {
ZStack(alignment: .leading) {
Rectangle()
.frame(width: UIScreen.main.bounds.width, height: 50)
.foregroundColor(Color.lokalZeroBlue)
Text(station.displayName)
.font(.title)
.foregroundColor(Color.white)
.padding(.leading)
}
MapView(latitude: station.latitude, longitude: station.longitude, span: 0.05)
.frame(height: UIScreen.main.bounds.height / 3)
.padding(.top, -8)
Form {
Toggle(isOn: $isDisplayed)
{ Text("Wetterstation anzeigen") }
}
Spacer()
}.colorScheme(.dark)
}
}
The desired behaviour would be that the action "PWSStore.shared.toggleIsDisplayed(station)" is triggered when the Toggle() changes its state.
In iOS 17 onChange
with a single parameter is deprecated - instead we should:
Use
onChange
with a two or zero parameter action closure instead.
struct ContentView: View {
@State private var isDisplayed = false
var body: some View {
Toggle("", isOn: $isDisplayed)
.onChange(of: isDisplayed) {
print("Action")
}
.onChange(of: isDisplayed) { oldValue, newValue in
// action...
print(oldValue, newValue)
}
}
}
We can also set the initial
parameter to specify whether the action should be run when the view initially appears.
struct ContentView: View {
@State private var isDisplayed = false
var body: some View {
Toggle("", isOn: $isDisplayed)
.onChange(of: isDisplayed, initial: true) {
print("Action")
}
}
}
If you're using iOS 14 and higher you can use onChange
:
struct ContentView: View {
@State private var isDisplayed = false
var body: some View {
Toggle("", isOn: $isDisplayed)
.onChange(of: isDisplayed) { value in
// action...
print(value)
}
}
}