FPL
FPL

Reputation: 466

Why does picker binding not update when using SwiftUI?

I have just begun learning Swift (and even newer at Swift UI!) so apologies if this is a newbie error.

I am trying to write a very simple programme where a user chooses someone's name from a picker and then sees text below that displays a greeting for that person.

But, the bound var chosenPerson does not update when a new value is picked using the picker. This means that instead of showing a greeting like "Hello Harry", "Hello no-one" is shown even when I've picked a person.


struct ContentView: View {

var people = ["Harry", "Hermione", "Ron"]
@State var chosenPerson: String? = nil

    var body: some View {
        NavigationView {
            Form {
        Section {
    Picker("Choose your favourite", selection: $chosenPerson) {
        ForEach ((0..<people.count), id: \.self) { person in
            Text(self.people[person])
            }
        }
        }

        Section{
            Text("Hello \(chosenPerson ?? "no-one")")
        }
        }
    }
   }
}

(I have included one or two pieces of the original formatting in case this is making a difference)

I've had a look at this question, it seemed like it might be a similar problem but adding .tag(person) to Text(self.people[person])did not solve my issue.

How can I get the greeting to show the picked person's name?

Upvotes: 4

Views: 2512

Answers (2)

GAlonso
GAlonso

Reputation: 686

The accepted answer is right if you are using simple arrays, but It was not working for me because I was using an array of custom model structs with and id defined as string, and in this situation the selection must be of the same type as this id. Example:

struct CustomModel: Codable, Identifiable, Hashable{

var id: String // <- ID of type string
var name: String
var imageUrl: String

And then, when you are going to use the picker:

struct UsingView: View {

@State private var chosenCustomModel: String = "" //<- String as ID
@State private var models: [CustomModel] = []


var body: some View {
 
        VStack{
            
                Picker("Picker", selection: $chosenCustomModel){
                        ForEach(models){ model in
                            Text(model.name)
                                .foregroundColor(.blue)
                        }
                    }
                }

Hope it helps somebody.

Upvotes: 1

matt
matt

Reputation: 534903

Bind to the index, not to the string. Using the picker, you are not doing anything that would ever change the string! What changes when a picker changes is the selected index.

struct ContentView: View {
    var people = ["Harry", "Hermione", "Ron"]
    @State var chosenPerson = 0
    var body: some View {
        NavigationView {
            Form {
                Section {
                    Picker("Choose your favourite", selection: $chosenPerson) {
                        ForEach(0..<people.count) { person in
                            Text(self.people[person])
                        }
                    }
                }
                Section {
                    Text("Hello \(people[chosenPerson])")
                }
            }
        }
    }
}

enter image description here

Upvotes: 16

Related Questions