【问题标题】:Adding a callback to a SwiftUI Picker向 SwiftUI Picker 添加回调
【发布时间】:2019-07-17 22:05:43
【问题描述】:

我正在尝试向 SwiftUI 选择器添加回调,但无法执行。 The didSet apparently does not execute when picker value changes.到目前为止,这是我尝试过的:

struct ContentView : View {
    @State private var picked: Int = 0 {didSet{print("here")}}
    var someData = ["a", "b", "c"]
    var body: some View {

        VStack {
            Picker(selection: $picked,
                   label: Text("")) {
                    ForEach(0 ..< someData.count)     {Text(self.someData[$0]).tag($0)}
            }
            .pickerStyle(.wheel)
            Text("you picked: \(someData[picked])")
        }
    }
}

【问题讨论】:

    标签: callback picker swiftui


    【解决方案1】:

    代码更新至 beta 6

    @State 变量永远不会执行 didSet,因为它不会改变。改变的是包装的价值。所以我能想到的唯一方法是在中间放置第二个绑定,作为中介,并传递值。这样,您就可以将回调放在那里。

    struct ContentView : View {
        @State private var picked: Int = 0
    
        var someData = ["a", "b", "c"]
        var body: some View {
    
            let p = Binding<Int>(get: {
                return self.picked
            }, set: {
                self.picked = $0
    
                // your callback goes here
                print("setting value \($0)")
            })
    
    
            return VStack {
                Picker(selection: p,
                       label: Text("")) {
                        ForEach(0 ..< someData.count) {
                            Text(self.someData[$0]).tag($0)
                        }
                }
                .pickerStyle(WheelPickerStyle())
                Text("you picked: \(someData[picked])")
            }
        }
    }
    

    【讨论】:

    • DOESNT COMPILE:函数声明了一个不透明的返回类型,但在其主体中没有返回语句来推断底层类型
    • 这只是一半。我似乎可以让它回来工作。假设您要转换通过绑定传入的字母“b”并使其成为选定按钮。我不能让它工作
    • @jimijon 这是一个小问题,与 SwiftUI 无关:只需在数组中查找项目索引:self.picked = self.someData.firstIndex(of: "b") ?? 0
    • 不是。设置好后尝试将绑定传递给视图。如何设置绑定:@Binding alphabetLetter:String。 ?然后您需要将 self.picked 设置为 self.someData.first ... 这会导致无限循环
    • Uau 不错的解决方案,效果很好!我需要这个来更新来自父视图的绑定变量。
    【解决方案2】:

    你可以使用 ObservableObject 来解决它

    
    import SwiftUI
    
    class PickerModel:ObservableObject{
        @Published var picked: Int = 0 {didSet{print("here")}}
    }
    
    struct Picker_Callback: View {
       @ObservedObject var pickerModal = PickerModel()
        var someData = ["a", "b", "c"]
        var body: some View {
    
            VStack {
                Picker(selection: self.$pickerModal.picked,
                       label: Text("")) {
                        ForEach(0 ..< someData.count)     {Text(self.someData[$0]).tag($0)}
                }
                //.pickerStyle(.wheel)
                Text("you picked: \(someData[self.pickerModal.picked])")
            }
        }
    }
    
    

    【讨论】:

      【解决方案3】:

      您不能在带有@State 属性包装器的变量上使用didSet 修饰符。

      State 包装器告诉 SwiftUI,包装后的值必须由 SwiftUI 框架本身管理。这意味着视图实际上并不包含该值,它只包含一个 State(它是不可变的),它提供对包装值的某种引用。

      实际上,您应该忘记 SwiftUI View 中的 didSet 回调。 View 协议需要body,它没有标记为mutating(SwiftUI 视图为struct)。所以View 基本上是不可变的。

      【讨论】:

      • 拉斐尔是 100% 正确的。 didSet 永远不会被调用。检查我的答案以获得解决方法。
      • .onChange 修饰符(用于 Picker 等) 可用,这在某些情况下可能就足够了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-19
      相关资源
      最近更新 更多