SwiftUI 选择器,选择作为结构

问题描述 投票:0回答:4

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

struct Pet: Identifiable, Codable, Hashable {

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

我从某个类中获取所有宠物,其中宠物被定义为@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("Pet", selection: $petSelection) {
ForEach(0 ..< Self.pet.count) { index in
    Text(Self.pet[index].name).tag(index)
    }

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

swift swiftui picker
4个回答
22
投票

简短回答:

tag
Picker
)中条目的
Text
关联的类型必须与用于存储选择的类型相同。

来自选择器文档

为选择输入参数使用可选值。为此,您需要将标签修饰符的输入显式转换为可选以进行匹配。有关示例,请参阅 tag(_:)

在您的示例中:您有

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

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

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

您已将选择定义为结构的

Optional
Pet?
。看来选择器无法正确处理可选结构作为其选择类型。

一旦您摆脱了可选选项,例如通过引入“虚拟/未选择的宠物”,

Picker
将再次开始工作:

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

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

@State private var petSelection: Pet = .emptySelection

我希望这也能帮助你。


4
投票

您可以使用以下方式:

 @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)
       }}}

2
投票

$petSelection
中的
Picker(selection:[...]
类型必须与结构中的
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
可识别,以从
id:
中删除参数
ForEach

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


2
投票

我就是这样做的:

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)
           }
       }

}
© www.soinside.com 2019 - 2024. All rights reserved.