简体   繁体   English

SwiftUI 选择器,选择作为结构

[英]SwiftUI Picker with selection as struct

Iam trying to use Picker as selection of struct.我正在尝试使用 Picker 作为结构的选择。 Let say I have a struct "Pet" like below假设我有一个像下面这样的结构“宠物”

struct Pet: Identifiable, Codable, Hashable {

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

I am getting all Pet's from some class, where Pets are defined as @Published var pets = Pet我从某个班级获得所有宠物,其中宠物被定义为@Published var pets = Pet

static let pets = Class().pets

I would like to be able to write a selection from picker to below variable:我希望能够将选择器中的选择写入以下变量:

@State private var petSelection: Pet?

Picker is:选择器是:

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

                    }
                }

Picker shows properly all avaliavble pets but when I chose one petSelection has been not changed (nil). Picker 正确显示了所有可用的宠物,但是当我选择了一个宠物时,Selection 没有改变(零)。 How should I mange it?我应该如何管理它?

Thanks!谢谢!

Edit:编辑:

Of course I know that I can use tag like below:当然,我知道我可以使用如下标签:

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

But wonder is it possible to use struct as selection.但是想知道是否可以使用 struct 作为选择。 Thanks谢谢

Short answer: The type associated with the tag of the entries in your Picker (the Text s) must be identical to the type used for storing the selection.简短回答:Picker条目tag关联的类型( Text s)必须与用于存储选择的类型相同。

In your example: You have an optional selection (probably to allow "empty selection") of Pet?在您的示例中:您有一个可选的选择(可能允许“空选择”) Pet? , but the array passed to ForEach is of type [Pet] . ,但传递给ForEach的数组是[Pet]类型。 You have to add therefore a .tag(item as Pet?) to your entries to ensure the selection works.因此,您必须在.tag(item as Pet?)添加一个.tag(item as Pet?)以确保选择有效。

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

Here follows my initial, alternate answer (getting rid of the optionality):以下是我最初的替代答案(摆脱可选性):

You have defined your selection as an Optional of your struct: Pet?您已将选择定义为结构的OptionalPet? . . It seems that the Picker cannot handle Optional structs properly as its selection type. Picker 似乎无法正确处理 Optional 结构作为其选择类型。

As soon as you get rid of the optional for example by introducing a "dummy/none-selected Pet", Picker starts working again:一旦您通过引入“虚拟/未选择的宠物”来摆脱可选的, Picker再次开始工作:

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

in your view initialise the selection:在您的视图中初始化选择:

@State private var petSelection: Pet = .emptySelection

I hope this helps you too.我希望这也能帮助你。

You use the following way:您使用以下方式:

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

the type of $petSelection in Picker(selection:[...] has to be the same type of id within your struct. So in your case you would have to change $petSelection to type if UUID since your items within the collection have UUID as identifier. Picker(selection:[...]$petSelection类型必须与结构中的id类型相同。因此,在您的情况下,您必须将$petSelection更改$petSelection类型 if UUID因为您的集合中的项目具有 UUID作为标识符。

Anyway since this is not what you're after, but your intention is to receive the Pet as a whole when selected.无论如何,因为这不是您所追求的,但您的目的是在选择时将Pet作为一个整体接收。 For that you will need a wrapper containing Pet as the id .为此,您将需要一个包含Pet作为id的包装器。 Since Pet is already Identifiable , there're only a few adjustments to do:由于Pet已经是Identifiable ,所以只需要做一些调整:

Create a wrapper having Pet as an id创建一个以Pet作为id的包装器

struct PetPickerItem {
    let pet: Pet?
}

Now wrap all collection items within the picker item现在将所有收集项包裹在选择器项中

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

You can now do minor adjustments like making PetPickerItem identifiable to remove the parameter id: from ForEach .您现在可以做一些小的调整,比如使PetPickerItem识别以从ForEach删除参数id: PetPickerItem

That's the best solution I came up with.这是我想出的最好的解决方案。

This is how I do it:这就是我的做法:

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

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM