How can I trigger an action when a swiftUI toggle() is toggled?
iOS 14+
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)
}
}
}
The cleanest approach in my opinion is to use a custom binding. With that you have full control when the toggle should actually switch
import SwiftUI
struct ToggleDemo: View {
@State private var isToggled = false
var body: some View {
let binding = Binding(
get: { self.isToggled },
set: {
potentialAsyncFunction($0)
}
)
func potentialAsyncFunction(_ newState: Bool) {
//something async
self.isToggled = newState
}
return Toggle("My state", isOn: binding)
}
}
iOS13+
Here is a more generic approach you can apply to any Binding
for almost all built in View
s like Pickers, Textfields, Toggle..
extension Binding {
func didSet(execute: @escaping (Value) -> Void) -> Binding {
return Binding(
get: { self.wrappedValue },
set: {
self.wrappedValue = $0
execute($0)
}
)
}
}
And usage is simply;
@State var isOn: Bool = false
Toggle("Title", isOn: $isOn.didSet { (state) in
print(state)
})
iOS14+
@State private var isOn = false
var body: some View {
Toggle("Title", isOn: $isOn)
.onChange(of: isOn) { _isOn in
/// use _isOn here..
}
}
Here is a version without using tapGesture.
@State private var isDisplayed = false
Toggle("", isOn: $isDisplayed)
.onReceive([self.isDisplayed].publisher.first()) { (value) in
print("New value is: \(value)")
}