3

i am using a Picker to show a segmented control and wish to know when the picker value changes so i can perform a non-UI action. Using the proposed onReceive() modifier (as suggested here) does not work as it is called every time the body is rendered.

Here's the code i have:

struct PickerView: View {

    @State private var weather = 0
    @State private var showMessage = false

    var body: some View {

        VStack(spacing: 24) {
            Picker(selection: $weather, label: Text("Weather")) {
                Image(systemName: "sun.max.fill").tag(0)
                Image(systemName: "cloud.sun.rain.fill").tag(1)
            }
            .pickerStyle(SegmentedPickerStyle())
            .frame(width: 120, height: 48)
            .onReceive([weather].publisher.first()) { connectionType in
                print("connection type is: \(connectionType)")
            }

            Button(action: { self.showMessage.toggle() }) {
                Text("Press Me")
            }

            if showMessage {
                Text("Hello World")
            }
        }
    }
}

The onReceive() block will get called any time the body is rendered, including the first time and any time the button (which toggles showing a message) is pressed.

Any ideas why this is happening and how i can only react to when the picker value is changed?

number4
  • 35
  • 4

1 Answers1

5

Here is possible solution instead of .onReceive

Picker(selection: Binding(           // << proxy binding
                get: { self.weather },
                set: { self.weather = $0
                    print("connection type is: \($0)")  // side-effect
                })
    , label: Text("Weather")) {
    Image(systemName: "sun.max.fill").tag(0)
    Image(systemName: "cloud.sun.rain.fill").tag(1)
}
Asperi
  • 228,894
  • 20
  • 464
  • 690