Is there a way to call a function when a SwiftUI Picker selection changes?

后端 未结 2 1514
时光说笑
时光说笑 2020-12-08 17:05

I would like to call a function when selectedOption\'s value changes. Is there a way to do this in SwiftUI similar to when editing a TextField?

Specifically, I would

相关标签:
2条回答
  • 2020-12-08 17:45

    If the @State value will be used in a View, you don't need extra variable name

      struct BuilderPicker: View {
    // let name: String = ""
     let options: Array<String> = ["1", "2","3","4","5"]
     @State var selectedOption = 0
     var body: some View {
        HStack {
            Text(options[selectedOption])
                .font(.body)
                .padding(.leading, 10)
            Picker(selection: $selectedOption, label:    Text(options[selectedOption])) {
                ForEach(0 ..< options.count) {
                    Text(self.options[$0]).tag($0)
                }
            }.pickerStyle(SegmentedPickerStyle())
                .padding(.trailing, 25)}
    //        }.onTapGesture {
    //            self.selectedOption = self.selectedOption == 0 ? 1 : 0
    //        }
            .padding(.init(top: 10, leading: 10, bottom: 10, trailing: 0))
            .border(Color.secondary, width: 3)
            .padding(.init(top: 0, leading: 15, bottom: 0, trailing: 15))
            .font(.body)
        }
    
    
     }
    

    If you need separated operation on the @State, the simplest way is adding one line : onReceive() to the view.

      HStack {
            Text("")
                .font(.body)
                .padding(.leading, 10)
            Picker(selection: $selectedOption, label: Text("")) {
                ForEach(0 ..< options.count) {
                    Text(self.options[$0]).tag($0)
                }
            }.pickerStyle(SegmentedPickerStyle())
                .padding(.trailing, 25)}
      //        }.onTapGesture {
     //            self.selectedOption = self.selectedOption == 0 ? 1 : 0
     //        }
            .padding(.init(top: 10, leading: 10, bottom: 10, trailing: 0))
            .border(Color.secondary, width: 3)
            .padding(.init(top: 0, leading: 15, bottom: 0, trailing: 15))
            .font(.body)
            .onReceive([self.selectedOption].publisher.first()) { (value) in
                print(value)
        }
    
    0 讨论(0)
  • 2020-12-08 17:50

    The previous solution will end up in an infinite loop if you update an ObservedObject in the callback since .onReceive is also called when the View got rendered.

    → A better approach is to use a .onChange method on the Binding itself:

    Picker(selection: $selectedOption.onChange(doSomething), label: Text("Hello world")) {
            // ...
        }
    

    To do so you need to write an extension for Binding like described here.

    0 讨论(0)
提交回复
热议问题