当 SwiftUI Picker 选择更改时,有没有办法调用函数?

Eli*_*ont 14 onchange picker swift swiftui

我想在 selectedOption 的值发生变化时调用一个函数。有没有办法在 SwiftUI 中做到这一点,类似于编辑 TextField 时?

具体来说,我想在用户更改 selectedOption 时保存所选选项。

这是我的选择器:

struct BuilderPicker: View {
    let name: String
    let options: Array<String>
    @State var selectedOption = 0
    var body: some View {
        HStack {
            Text(name)
                .font(.body)
                .padding(.leading, 10)
            Picker(selection: $selectedOption, label: Text(name)) {
                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)
    }

}
Run Code Online (Sandbox Code Playgroud)

我还是 SwiftUI 的新手,希望得到一些帮助。谢谢!

E.C*_*oms 21

如果 @State 值将在视图中使用,则不需要额外的变量 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)
    }


 }
Run Code Online (Sandbox Code Playgroud)

如果需要对@State 进行单独操作,最简单的方法是在视图中添加一行:onReceive()。

  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)
    }
Run Code Online (Sandbox Code Playgroud)

  • 这可行,但是“[self.selectedOption].publisher.first()”w00t?:) (7认同)
  • 您可以使用“Just(self.selectedOption)” (3认同)
  • 如果您在回调中更新 ObservedObject,则可能会进入无限循环。你很快就会知道,因为它会锁定用户界面并且你的记忆力会激增。 (3认同)
  • `[self.selectedOption].publisher.first()` 是公共 API 吗?它感觉不像公共 API,但天哪,它确实有效。 (2认同)

ixa*_*any 6

ObservedObject如果您在回调中更新 an ,则先前的解决方案将最终陷入无限循环,因为.onReceive在渲染视图时也会调用它。

\n

.onChange\xe2\x86\x92 更好的方法是在 Binding 本身上使用方法:

\n
Picker(selection: $selectedOption.onChange(doSomething), label: Text("Hello world")) {\n        // ...\n    }\n
Run Code Online (Sandbox Code Playgroud)\n

为此,您需要编写一个类似于此处所述的extensionfor 。Binding

\n

  • 你对循环的看法肯定是正确的。但是,您可以在 Picker 本身上使用 .onChange(of: Perform:) 修饰符,而不是在 Binding 上使用扩展,其中 of: 是您的 @State 变量,perform: 是您要执行的操作。 (7认同)