swiftswiftui

Is there a SwiftUI Picker onChange equivalent?


I want to change another unrelated @State variable when a Picker gets changed, but there is no onChanged and it's not possible to put a didSet on the pickers @State. Is there another way to solve this?


Solution

  • Deployment target of iOS 14 or newer

    Apple has provided a built in onChange extension to View, which can be used like this:

    struct MyPicker: View {
        @State private var favoriteColor = 0
    
        var body: some View {
            Picker(selection: $favoriteColor, label: Text("Color")) {
                Text("Red").tag(0)
                Text("Green").tag(1)
            }
            .onChange(of: favoriteColor) { tag in print("Color tag: \(tag)") }
        }
    }
    

    Deployment target of iOS 13 or older

    struct MyPicker: View {
        @State private var favoriteColor = 0
    
        var body: some View {
            Picker(selection: $favoriteColor.onChange(colorChange), label: Text("Color")) {
                Text("Red").tag(0)
                Text("Green").tag(1)
            }
        }
    
        func colorChange(_ tag: Int) {
            print("Color tag: \(tag)")
        }
    }
    

    Using this helper

    extension Binding {
        func onChange(_ handler: @escaping (Value) -> Void) -> Binding<Value> {
            return Binding(
                get: { self.wrappedValue },
                set: { selection in
                    self.wrappedValue = selection
                    handler(selection)
            })
        }
    }