Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I trigger an action when a swiftUI toggle() is toggled?

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.

like image 910
Brezentrager Avatar asked Jul 11 '19 19:07

Brezentrager


People also ask

How do I toggle a state variable in SwiftUI?

You can create a toggle or switch by simply typing Toggle() . To configure toggle, we have to pass the parameter. The parameter name is isOn of type Binding<Bool> , which defines the state of the toggle (i.e., whether it's on or off). Inside the toggle body, we can define the text that'll appear beside the toggle view.

How do I change the toggle color in SwiftUI?

By default, SwiftUI uses the UISwitch view from UIKit to represent a Toggle. There is no way to change the tint color of Toggle from SwiftUI, but we can use UIAppearance API from UIKit to set the tint color for all UISwitch instances across the app.


3 Answers

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)
            }
    }
}
like image 57
pawello2222 Avatar answered Oct 17 '22 02:10

pawello2222


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)")           
   }
like image 45
TheLegend27 Avatar answered Oct 17 '22 00:10

TheLegend27


iOS13+

Here is a more generic approach you can apply to any Binding for almost all built in Views 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..
        }
}
like image 40
Enes Karaosman Avatar answered Oct 17 '22 02:10

Enes Karaosman