Nicolas
Nicolas

Reputation: 269

How to store selection of multiple Pickers?

I have 4 dogs - represented by 4 Pickers - and each one of them has a favourite treat. How can I store the selection of each Picker? I tried storing it in a dictionary, but when clicking on one of the treats nothing gets selected and the Picker view also does not get dismissed.

import SwiftUI
import OrderedCollections

enum Dog : String, CaseIterable, Identifiable {
    var id: Self { self }
    case Anton, Ben, Charlie, Didi
}

struct MainConstants {
    let treats : OrderedDictionary <String, Int> = [
        "Bone" : 123,
        "Sausage" : 456,
        "Cookies" : 789
    ]
}


struct FavouriteTreatsView: View {
    
    let constants = MainConstants()
    
    @State var favouriteTreats : [Dog : String] = [:]
    
    var body: some View {
        NavigationView {
            Form {
                ForEach (Dog.allCases) {dog in
                    Picker(dog.rawValue ,selection: $favouriteTreats[dog]) {
                        ForEach (constants.treats.keys, id: \.self) {treat in
                            Text(treat)
                        }
                    }
                }
            }
        }
    }
}

struct FavoriteTreatsView_Previews: PreviewProvider {
    static var previews: some View {
        FavouriteTreatsView()
    }
}

Upvotes: 0

Views: 668

Answers (1)

HunterLion
HunterLion

Reputation: 4006

I don't know about treating dogs, however the example below works well with lions...

First, you can have a dedicated view for each single picker - that view will store the treat of each lion on a @State var. You use the .id() modifier to tell the picker what value needs to be stored.

The view will also have a @Binding var that will receive the dictionary, to store the treat selected on the right lion.

In that picker view, you listen to changes in the treat: when a treat is selected, you store that value in the dictionary passed with the binding var.

So, assuming they are lions, here's the picker view:

struct TreatMe: View {
    let constants = MainConstants()

    // treat for a single Lion
    @State private var treat = ""
    
    // The dictionary that will be updated after the treat is selected
    @Binding var favouriteTreats: [Lion: String]
    
    // the Lion that will receive the treat
    let lion: Lion
    
    var body: some View {
        Picker(lion.rawValue ,selection: $treat) {
            ForEach (constants.treats.keys, id: \.self) {treat in
                Text(treat)
                
                    // This will ensure the right value is stored
                    .id(treat)
            }
        }
        
        // Listen to changes in the treat, then store it in the dictionary
        .onChange(of: treat) { value in
            favouriteTreats[lion] = value
        }
    }
}

You call it from the FavouriteTreatsView:

struct FavouriteTreatsView: View {
    
    @State var favouriteTreats : [Lion : String] = [:]
    
    var body: some View {
        NavigationView {
            Form {
                ForEach (Lion.allCases) {lion in
                    
                    // Pass the variables
                    TreatMe(favouriteTreats: $favouriteTreats, lion: lion)
                }
            }
        }
    }
}

enter image description here

Upvotes: 1

Related Questions