代码之家  ›  专栏  ›  技术社区  ›  Duncan C

如何动态填充SwiftUI选取器(分段控件)

  •  0
  • Duncan C  · 技术社区  · 2 年前

    我让拾取器处理静态项目列表。

    我一直纠结于如何使用动态数据(来自 @state 变量或环境变量。)

    这个非常简单的SwiftUI应用程序创建了一个分段控件,但它不显示当前选择,也不允许用户选择:

    import SwiftUI
    
    struct ContentView: View {
        @State private var colors = ["Red", "Green", "Blue"]
        @State private var selectedColor: Int = 0
        
        var body: some View {
            VStack {
                HStack {
                    Spacer().frame(width: 30)
                    Picker("What is your favorite color?", selection: $selectedColor) {
                        ForEach(colors, id: \.self) { aValidColor in
                            Text(aValidColor)
                        }
                    }
                    Spacer().frame(width: 30)
                }
                .pickerStyle(.segmented)
                Spacer().frame(height: 30)
                Text("Value: \(colors[selectedColor])")
            }
        }
    }
    

    (如果重要的话,我使用的是Xcode 15.0 beta 3。)

    我认为这与我的ForEach中项目的ID和Picker中分配给Text项目的标记值有关,但我不知道如何使其工作。

    编辑:

    我通过从 Array 属于 String 对象的数组 Identifiable Struct s、 并且使每个结构的id作为其在数组中的索引:

    import SwiftUI
    
    struct AColor: Identifiable {
        let name: String
        let id: Int
    }
    
    struct ContentView: View {
        @State private var colors = [
            AColor(name: "Red", id: 0),
            AColor(name:"Green", id: 1),
            AColor(name:"Blue", id: 2)
        ]
        @State private var selectedColor: Int = 0
        
        var body: some View {
            VStack {
                HStack {
                    Spacer().frame(width: 30)
                    Picker("What is your favorite color?", selection: $selectedColor) {
                        ForEach(colors) { aValidColor in
                            Text(aValidColor.name)
                        }
                    }
                    Spacer().frame(width: 30)
                }
                .pickerStyle(.segmented)
                Spacer().frame(height: 30)
                Text("Value: \(colors[selectedColor].name)")
            }
        }
    }
    

    不过,这并不理想,因为现在我必须维护一个structs数组,其中数组中的每个项都有一个值,该值包含数组中的索引。啊。

    似乎应该有一些使用方法 enumerated() 以获得对象及其索引的数组,但ForEach想要一个Binding,而不是枚举序列。(我仍在试着把我的头缠在捆绑物上。)

    2 回复  |  直到 2 年前
        1
  •  1
  •   Benzy Neez    2 年前

    数组包含字符串,但Binding指向Int。

    因此,这将是另一种解决方法:

    ForEach(Array(colors.enumerated()), id: \.element) { index, color in
        Text(color).tag(index)
    }
    
        2
  •  1
  •   jnpdx    2 年前

    的类型 selection 参数和 tag ForEach 必须匹配。因为你正在使用 id: \.self ,项目被标记为 String

    因此:

    struct ContentView: View {
        @State private var colors = ["Red", "Green", "Blue"]
        @State private var selectedColor: String = "Red"
        
        var body: some View {
            VStack {
                HStack {
                    Spacer().frame(width: 30)
                    Picker("What is your favorite color?", selection: $selectedColor) {
                        ForEach(colors, id: \.self) { aValidColor in
                            Text(aValidColor)
                        }
                    }
                    Spacer().frame(width: 30)
                }
                .pickerStyle(.segmented)
                Spacer().frame(height: 30)
                Text("Value: \(selectedColor)")
            }
        }
    }
    

    如果您真的想使用索引,请包括 标签 :

    struct ContentView: View {
        @State private var colors = ["Red", "Green", "Blue"]
        @State private var selectedColor: Int = 0
        
        var body: some View {
            VStack {
                HStack {
                    Spacer().frame(width: 30)
                    Picker("What is your favorite color?", selection: $selectedColor) {
                        ForEach(Array(colors.enumerated()), id: \.element) { (index, item) in
                            Text(item).tag(index)
                        }
                    }
                    Spacer().frame(width: 30)
                }
                .pickerStyle(.segmented)
                Spacer().frame(height: 30)
                Text("Value: \(colors[selectedColor])")
            }
        }
    }