向 SwiftUI Picker 添加回调

Posted

技术标签:

【中文标题】向 SwiftUI Picker 添加回调【英文标题】:Adding a callback to a 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 didSetprint("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])")
        
    

【问题讨论】:

【参考方案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 didSetprint("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 等) 可用,这在某些情况下可能就足够了。

以上是关于向 SwiftUI Picker 添加回调的主要内容,如果未能解决你的问题,请参考以下文章

在 SwiftUI 的 Picker 中添加新元素

SwiftUI:将动画添加到 Picker 而不将其添加到值中

SwiftUI:添加元素时选择器内容未刷新

SwiftUI PickerView 与工作回调如何?

SwiftUI 拖放文件

SwiftUI Segmented Picker 元素为灰色且禁用