I have a Picker embedded in Form, however I can't get it working that it shows a checkmark and the selected value in the form.
NavigationView {
Form {
Section {
Picker(selection: $currencyCode, label: Text("Currency")) {
ForEach(0 ..< codes.count) {
Text(self.codes[$0]).tag($0)
}
}
}
}
}
Picker is a control in SwiftUI which allows you to select a value from a list of possible options. In order to properly use a Picker, you need to back it with an array of possible options to choose from and a State variable storing the index of selected option in the array.
There’s lots of good stuff in SwiftUI. One missing control is old fashioned checkbox like I have on the web or on my Mac. There is a way to make a checkbox with a Toggle control. However, as a bit of a intro to the philosophy of SwiftUI, let look at creating a checkbox.
I can use the Image object in SwiftUI with the systemName parameter to get a SFSymbol from SwiftUI. The checked square is simply the word checkmark before the square. I just have to switch between them. That will need some kind of variable.
By wrapping the Picker in a From, we’re giving it extra functionality – the picker now becomes a single horizontal row with selected value in it. Tapping on the picker navigates away to a new view which contains a list of possible options. Tapping a desired option, selects it and navigates back to the original view.
TL;DR
Your variable currencyCode
does not match the type of the ID for each element in your ForEach
. Either iterate over the codes in your ForEach
, or pass your Picker
an index.
Below are three equivalent examples. Notice that the @State
variable which is passed to Picker
always matches the ID of element that the ForEach
iterates over:
Also note that I have picked a default value for the @State
variable which is not in the array ("", -1, UUID()), so nothing is shown when the form loads. If you want a default option, just make that the default value for your @State
variable.
Example 1: Iterate over codes (i.e. String)
struct ContentView: View {
@State private var currencyCode: String = ""
var codes: [String] = ["EUR", "GBP", "USD"]
var body: some View {
NavigationView {
Form {
Section {
Picker(selection: $currencyCode, label: Text("Currency")) {
// ID is a String ----v
ForEach(codes, id: \.self) { (string: String) in
Text(string)
}
}
}
}
}
}
}
Example 2: Iterate over indices (i.e. Int)
struct ContentView: View {
@State private var selectedIndex: Int = -1
var codes: [String] = ["EUR", "GBP", "USD"]
var body: some View {
NavigationView {
Form {
Section {
Picker(selection: $selectedIndex, label: Text("Currency")) {
// ID is an Int --------------v
ForEach(codes.indices, id: \.self) { (index: Int) in
Text(self.codes[index])
}
}
}
}
}
}
}
Example 3: Iterate over an identifiable struct by its ID type (i.e. UUID)
struct Code: Identifiable {
var id = UUID()
var value: String
init(_ value: String) {
self.value = value
}
}
struct ContentView: View {
@State private var selectedUUID = UUID()
var codes = [Code("EUR"), Code("GBP"), Code("USD")]
var body: some View {
NavigationView {
Form {
Section {
Picker(selection: $selectedUUID, label: Text("Currency")) {
// ID is a UUID, because Code conforms to Identifiable
ForEach(self.codes) { (code: Code) in
Text(code.value)
}
}
}
}
}
}
}
It's difficult to say, what you are doing wrong, because your example doesn't include the declaration of codes
or currencyCode
. I suspect that the problem is with the binding being of a different type than the tag you are setting on a picker (which is an Int in your case).
Anyway, this works:
struct ContentView: View {
let codes = Array(CurrencyCode.allCases)
@State private var currencyCode: CurrencyCode?
var body: some View {
NavigationView {
Form {
Section {
Picker("Currency",
selection: $currencyCode) {
ForEach(codes, id: \.rawValue) {
Text($0.rawValue).tag(Optional<CurrencyCode>.some($0))
}
}
}
}
}
}
}
enum CurrencyCode: String, CaseIterable {
case eur = "EUR"
case gbp = "GBP"
case usd = "USD"
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With