SwiftUI Picker onChange or equivalent?

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)
        })
    }
}

First of all, full credit to ccwasden for the best answer. I had to modify it slightly to make it work for me, so I'm answering this question hoping someone else will find it useful as well.

Here's what I ended up with (tested on iOS 14 GM with Xcode 12 GM)

struct SwiftUIView: View {
    @State private var selection = 0

    var body: some View {
        Picker(selection: $selection, label: Text("Some Label")) {
            ForEach(0 ..< 5) {
                Text("Number \($0)") }
        }.onChange(of: selection) { _ in
            print(selection)
        }
        
    }
}

The inclusion of the "_ in" was what I needed. Without it, I got the error "Cannot convert value of type 'Int' to expected argument type '()'"

Tags:

Swiftui