当SwiftUI选取器选择更改EnvironmentObject时,是否有方法调用函数



我正在使用一个SwiftUI表单,它更新EnvironmentObject的值。当Picker的值发生变化时,我需要调用一个函数,但我发现的每一种方法要么非常混乱,要么会导致其他问题。我正在寻找Slider的类似工作方式,但似乎没有。没有任何解决方案的基本代码在这里:

class ValueHolder : ObservableObject {
@Published var sliderValue : Float = 0.5
static let segmentedControlValues : [String] = ["one", "two", "three", "four", "five"]
@Published var segmentedControlValue : Int = 3
}
struct ContentView: View {
@EnvironmentObject var valueHolder : ValueHolder
func sliderFunction() {
print(self.valueHolder.sliderValue)
}
func segmentedControlFunction() {
print(ValueHolder.segmentedControlValues[self.valueHolder.segmentedControlValue])
}
var body: some View {
Form {
Text("(self.valueHolder.sliderValue)")
Slider(value: self.$valueHolder.sliderValue, onEditingChanged: {_ in self.sliderFunction()
})
Text("(ValueHolder.segmentedControlValues[self.valueHolder.segmentedControlValue])")
Picker("", selection: self.$valueHolder.segmentedControlValue) {
ForEach(0..<ValueHolder.segmentedControlValues.count) {
Text("(ValueHolder.segmentedControlValues[$0])")
}
}.pickerStyle(SegmentedPickerStyle())
}
}
}

在这里回顾了这个类似(但不同(的问题后:当SwiftUI选取器的选择发生变化时,有没有方法调用函数?我尝试过使用onReceive((,如下所示,但当Slider值发生变化时,也会调用它,从而导致不需要的行为。

.onReceive([self.valueHolder].publisher.first(), perform: {_ in
self.segmentedControlFunction()
})

我已尝试更改onReceive的参数,以便仅按该值进行筛选。传递的值是正确的,但当滑块移动时,segmentedControlFunction仍然会被调用,而不仅仅是当选择器发生变化时。

.onReceive([self.valueHolder.segmentedControlValue].publisher.first(), perform: {_ in
self.segmentedControlFunction()
})

如何以类似于sliderFunction的方式调用segmentedControlFunction?

有一种更简单的方法,看起来更适合我

通用模式如下

Picker("Label", selection: Binding(    // proxy binding
get: { self.viewModel.value },     // get value from storage
set: {
self.viewModel.value = $0  // set value to storage
self.anySideEffectFunction() // didSet function
}) {
// picker content
}

当我验证原始问题并修改代码时,我意外地发现了我认为可能是最好的解决方案。所以,如果它能帮助其他人,这里是:

struct ContentView: View {
@EnvironmentObject var valueHolder : ValueHolder
@State private var sliderValueDidChange : Bool = false
func sliderFunction() {
if self.sliderValueDidChange {
print("Slider value: (self.valueHolder.sliderValue)n")
}
self.sliderValueDidChange.toggle()
}
var segmentedControlValueDidChange : Bool {
return self._segmentedControlValue != self.valueHolder.segmentedControlValue
}
@State private var _segmentedControlValue : Int = 0
func segmentedControlFunction() {
self._segmentedControlValue = self.valueHolder.segmentedControlValue
print("SegmentedControl value: (ValueHolder.segmentedControlValues[self.valueHolder.segmentedControlValue])n")
}

var body: some View {
Form {
Text("(self.valueHolder.sliderValue)")
Slider(value: self.$valueHolder.sliderValue, onEditingChanged: {_ in self.sliderFunction()
})
Text("(ValueHolder.segmentedControlValues[self.valueHolder.segmentedControlValue])")
Picker("", selection: self.$valueHolder.segmentedControlValue) {
ForEach(0..<ValueHolder.segmentedControlValues.count) {
Text("(ValueHolder.segmentedControlValues[$0])")
}
}.pickerStyle(SegmentedPickerStyle())
.onReceive([self._segmentedControlValue].publisher.first(), perform: {_ in
if self.segmentedControlValueDidChange {
self.segmentedControlFunction()
}
})
}
}
}

请注意,onReceive((用于一个新的@State属性,该属性与Bool配对,用于评估它是否与@EnvironmentObject对应的属性相同。然后在函数调用中更新@State值。还要注意的是,在解决方案中,我更改了sliderFunction的工作方式,使其仅在@EnvironmentObject值实际更改时调用一次。这有点麻烦,但Slider和Picker在更新值和调用各自的函数时都以相同的方式工作。

最新更新