SwiftUI : Picker does not update correctly when changing datasource
I'm not sure why SwiftUI behaves like this, seems like a bug to me (Correct me if I'm wrong). All I can suggest is to add separate pickers for temperature and length and hide those based on the current selected type. For code re-usability I've added the picker to another file.
MyCustomPicker
struct MyCustomPicker: View {
var pickerData: [String]
@Binding var binding: Int
var body: some View {
Picker("Convert", selection: $binding) {
ForEach(0 ..< pickerData.count, id: \.self)
{ i in
Text(self.pickerData[i])
}
}
.pickerStyle(SegmentedPickerStyle())
}
}
ContentView
struct ContentView: View {
@State var selectedType = 0
@State var inputTempUnit = 0
@State var outputTempUnit = 1
@State var inputLenUnit = 0
@State var outputLenUnit = 1
let arrTypes = ["Temperature", "Length"]
let tempData = ["Celsius", "Fahrenheit", "Kelvin"]
let lenData = ["meters", "kilometers", "feet", "yards", "miles"]
var body: some View {
NavigationView {
Form {
Section(header: Text("Choose type")) {
MyCustomPicker(pickerData: arrTypes, binding: $selectedType)
}
Section(header: Text("From")) {
if selectedType == 0 {
MyCustomPicker(pickerData: tempData, binding: $inputTempUnit)
} else {
MyCustomPicker(pickerData: lenData, binding: $inputLenUnit)
}
}
Section(header: Text("To")) {
if selectedType == 0 {
MyCustomPicker(pickerData: tempData, binding: $outputTempUnit)
} else {
MyCustomPicker(pickerData: lenData, binding: $outputLenUnit)
}
}
}
}
}
}
Note: You have to use different state variables to keep track the temperature and length selection.
Nick Polychronakis solved it in this fork: https://github.com/nickpolychronakis/100DaysOfSwiftUI/tree/master/UnitCoverter
The solution is to add .id(:identifier:) to your picker so it is unique.
Observable var:
@State var unit = 0
Main picker:
Picker("Length", selection: $unit) {
ForEach(0 ..< inputUnitTypes.count) {
Text("\(self.inputUnitTypes[$0].description)")
}
}
.pickerStyle(SegmentedPickerStyle())
One of secondary pickers which content is determined by the unit variable.
Picker("Length", selection: $inputUnit) {
ForEach(0 ..< selected.count) {
Text("\(self.selected[$0].description)")
}
}
.id(unit)