I'm trying up dynamically add new rows to a Picker
as follows:
class ViewModel: ObservableObject {
@Published private (set) var drinks = ["Tea", "Coffee", "Wine"]
func addDrink(_ drink: String) {
drinks.append(drink)
}
}
struct PickerTest: View {
@State private var selectedDrink = "Tea"
@State private var customDrink = ""
@ObservedObject private var viewModel = ViewModel()
var body: some View {
VStack {
HStack {
TextField("Enter a drink", text: $customDrink)
Spacer()
Button("Add") {
self.viewModel.addDrink(self.customDrink)
}
}
Picker("Drinks", selection: $selectedDrink) { // Removing the wrapping Picker works
ForEach(viewModel.drinks, id: \.self) { drink in
Text(drink)
}
}
}.padding().labelsHidden()
}
}
This doesn't work. If I remove the Picker
wrapping the ForEach
, the ForEach
updates as expected.
Is there a way to update the Picker
dynamically?
It looks like Picker
s bug - I hope, that Apple fixes it in future releases of SwiftUI.
I found ugly (I really don't like it) workaround for this problem:
class ViewModel: ObservableObject {
@Published var selectedDrink = "Tea"
@Published var drinks = ["Tea", "Coffee", "Wine"]
@Published var drinksChanged = true
func addDrink(_ drink: String) {
drinks.append(drink)
drinksChanged.toggle()
}
}
struct DrinksPicker: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
Picker("Drinks", selection: $viewModel.selectedDrink) {
ForEach(viewModel.drinks, id: \.self) { drink in
Text(drink)
}
}
}
}
struct PickerTest: View {
@State private var customDrink = ""
@ObservedObject private var viewModel = ViewModel()
var body: some View {
VStack {
HStack {
TextField("Enter a drink", text: $customDrink)
Spacer()
Button("Add") {
self.viewModel.addDrink(self.customDrink)
self.customDrink = ""
}
}
if viewModel.drinksChanged {
DrinksPicker(viewModel: viewModel)
} else {
DrinksPicker(viewModel: viewModel)
}
}.padding().labelsHidden()
}
}
You can also hide this if
-else
in some another container:
struct DrinksPickerContainer: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
Group {
if viewModel.drinksChanged {
DrinksPicker(viewModel: viewModel)
} else {
DrinksPicker(viewModel: viewModel)
}
}
}
}
and then use only DrinksPickerContainer(viewModel: viewModel)
in PickerTest