【问题标题】:SwiftUI Picker with selection as structSwiftUI Picker 选择结构
【发布时间】:2019-12-18 21:55:09
【问题描述】:

我正在尝试使用 Picker 作为结构的选择。假设我有一个结构“宠物”,如下所示

struct Pet: Identifiable, Codable, Hashable {

    let id = UUID()
    let name: String
    let age: Int
}

我从某个类中获取所有 Pet,其中 Pets 被定义为 @Published var pets = Pet

static let pets = Class().pets

我希望能够将选择器的选择写入以下变量:

@State private var petSelection: Pet?

选择器是:

Picker("Pet", selection: $petSelection){
                    ForEach(Self.pets) { item in
                        Text(item.name)

                    }
                }

Picker 正确显示了所有可用的宠物,但是当我选择一个时 petSelection 没有改变(nil)。我应该如何管理它?

谢谢!

编辑:

当然我知道我可以使用如下标签:

Picker("Pet", selection: $petSelection) {
ForEach(0 ..< Self.pet.count) { index in
    Text(Self.pet[index].name).tag(index)
    }

但是想知道是否可以使用 struct 作为选择。谢谢

【问题讨论】:

    标签: swift swiftui picker


    【解决方案1】:

    简短回答:PickerTexts)中条目的tag 关联的类型必须与用于存储选择的类型相同。 p>

    在您的示例中:您有Pet? 的可选选择(可能允许“空选择”),但传递给ForEach 的数组类型为[Pet]。因此,您必须在您的条目中添加 .tag(item as Pet?) 以确保选择有效。

    ForEach(Self.pets) { item in
        Text(item.name).tag(item as Pet?)
    }
    

    下面是我最初的替代答案(摆脱可选性):

    您已将您的选择定义为结构的OptionalPet?。似乎 Picker 无法正确处理 Optional 结构作为其选择类型。

    一旦您通过引入“虚拟/未选择宠物”来摆脱可选的,Picker 就会再次开始工作:

    extension Pet {
        static let emptySelection = Pet(name: "", age: -1)
    }
    

    在您的视图中初始化选择:

    @State private var petSelection: Pet = .emptySelection
    

    我希望这对你也有帮助。

    【讨论】:

      【解决方案2】:

      您使用以下方式:

       @Published var  pets: [Pet?] = [ nil, Pet(name: "123", age: 23), Pet(name: "123dd", age: 243),]
      
           VStack{
            Text(petSelection?.name ??  "name")
            Picker("Pet", selection: $petSelection){
               ForEach(Self.pets, id: \.self) { item in
                  Text(item?.name ?? "name").tag(item)
             }}}
      

      【讨论】:

        【解决方案3】:

        Picker(selection:[...]$petSelection 的类型必须与结构中id 的类型相同。 因此,在您的情况下,您必须将 $petSelection 更改为输入 if UUID,因为集合中的项目具有 UUID 作为标识符。

        无论如何,因为这不是您所追求的,但您的意图是在选择时将Pet 作为一个整体接收。为此,您需要一个包含Pet 的包装器作为id。由于Pet 已经是Identifiable,因此只需要做一些调整:

        创建一个将Pet 作为id 的包装器

        struct PetPickerItem {
            let pet: Pet?
        }
        

        现在将所有集合项包装在选择器项中

        Picker("Pet", selection: $petSelection) {
            ForEach(Self.pets.map(PetPickerItem.init), id: \.pet) {
                Text("\($0.pet?.name ?? "None")")
            }
        }
        

        您现在可以进行一些小的调整,例如使 PetPickerItem 可识别,以从 ForEach 中删除参数 id:

        这是我想出的最佳解决方案。

        【讨论】:

          【解决方案4】:

          这就是我的做法:

          struct Language: Identifiable, Hashable  {
              var title: String
              var id: String
          }
          
          
          struct PickerView: View {
          
               var languages: [Language] = [Language(title: "English", id: "en-US"), Language(title: "German", id: "de-DE"), Language(title: "Korean", id: "ko-KR")]
               @State private var selectedLanguage = Language(title: "German", id: "de-DE")
          
               var body: some View {
                  Picker(selection: $selectedLanguage, label: Text("Front Description")) {
                      ForEach(self.languages, id: \.self) {language in
                          Text(language.title)
                     }
                 }
          
          }
          

          【讨论】:

            猜你喜欢
            • 2020-04-04
            • 2020-05-05
            • 1970-01-01
            • 2022-10-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-08-19
            相关资源
            最近更新 更多