简体   繁体   中英

SwiftUI Picker Help — Populating picker based on the selection of another picker

I am trying to populate a picker based on the selection of another picker. I am new to Swift and have been beating my head on this for way too long. I am sure its not as difficult as I am making it but I would appreciate any assistance.

I think my biggest issue is passing the selection of the first picker to the array name of the second. I have used switch case, tried to pass the selection raw value...etc. Below is a sample of what I would like it to look like without the binding of the pickers. Thanks

import SwiftUI

struct veggie: View {
    let veggies = ["Beans", "Corn", "Potatoes"]
    let beanList = ["Pole", "String", "Black"]
    let cornList = ["Peaches & Cream", "Sweet"]
    let potatoList = ["Yukon Gold", "Idaho"]
    @State private var selectedVeggie = "Bean"
    @State private var selectedBean = "Pole"
    @State private var selectedType = ""
    
            var body: some View {
                NavigationView{
                    VStack{
                        Form{
                            Picker("Please choose a veggie", selection: $selectedVeggie)
                                {
                                ForEach(veggies, id: \.self) {
                                    Text($0)
                                }
                            }
                            Text("You selected \(selectedVeggie)")
                            Picker("Type", selection: $selectedBean)
                                {
                                ForEach(beanList, id: \.self) {
                                    Text($0)
                                }
                            }
                        }
                    }     .navigationTitle("Veggie Picker")
                }
            }
        }

I'm imagining that you want this to be somewhat dynamic and not hardcoded with if statements. In order to accomplish that, I setup an enum with the veggie types and then a dictionary that maps the veggie types to their subtypes. Those look like:

enum VeggieType : String, CaseIterable {
    case beans, corn, potatoes
}

let subTypes : [VeggieType: [String]] = [.beans: ["Pole", "String", "Black"],
                                         .corn: ["Peaches & Cream", "Sweet"],
                                         .potatoes: ["Yukon Gold", "Idaho"]]

Then, in the view, I did this:

struct ContentView: View {
    @State private var selectedVeggie : VeggieType = .beans
    @State private var selectedSubtype : String?
    
    var subtypeList : [String] {
        subTypes[selectedVeggie] ?? []
    }
    var body: some View {
        NavigationView{
            VStack{
                Form{
                    Picker("Please choose a veggie", selection: $selectedVeggie)
                    {
                        ForEach(VeggieType.allCases, id: \.self) {
                            Text($0.rawValue.capitalized)
                        }
                    }
                    Text("You selected \(selectedVeggie.rawValue.capitalized)")
                    Picker("Type", selection: $selectedSubtype)
                    {
                        ForEach(subtypeList, id: \.self) {
                            Text($0).tag($0 as String?)
                        }
                    }
                }
            }     .navigationTitle("Veggie Picker")
        }
    }
}

The selectedVeggie is now typed with VeggieType . The selectedSubtype is an optional String that doesn't have an initial value (although you could set one if you want).

The first picker goes through all of the cases of VeggieType . The second one dynamically changes based on the computed property subtypeList which grabs the item from the subTypes dictionary I had made earlier.

The tag item is important -- I had to make the tag as String? because SwiftUI wants the selection parameter and the tag() to match exactly.


Note: you say you're new to Swift, so I'll mention that you had named your view `veggie` -- in Swift, normally types have capital names. I named mine `ContentView`, but you could rename it `VeggieView` or something like that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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