Reputation: 55
I'm quite new to SwiftUI and I'm wondering how I should use a picker in an update view correctly.
At the moment I have a form and load the data in with .onAppear()
. That works fine but when I try to pick something and go back to the update view the .onAppear()
gets called again and I loose the picked value.
In the code it looks like this:
import SwiftUI
struct MaterialUpdateView: View {
// Bindings
@State var material: Material
// Form Values
@State var selectedUnit = ""
var body: some View {
VStack(){
List() {
Section(header: Text("MATERIAL")){
// Picker for the Unit
Picker(selection: $selectedUnit, label: Text("Einheit")) {
ForEach(API().units) { unit in
Text("\(unit.name)").tag(unit.name)
}
}
}
}
.listStyle(GroupedListStyle())
}
.onAppear(){
prepareToUpdate()
}
}
func prepareToUpdate() {
self.selectedUnit = self.material.unit
}
}
Does anyone has experience with that problem or am I doing something terribly wrong?
Upvotes: 1
Views: 319
Reputation: 2304
You need to create a custom binding which we will implement in another subview. This subview will be initialised with the binding vars selectedUnit
and material
First, make your MaterialUpdateView
:
struct MaterialUpdateView: View {
// Bindings
@State var material : Material
// Form Values
@State var selectedUnit = ""
var body: some View {
NavigationView {
VStack(){
List() {
Section(header: Text("MATERIAL")) {
MaterialPickerView(selectedUnit: $selectedUnit, material: $material)
}
.listStyle(GroupedListStyle())
}
.onAppear(){
prepareToUpdate()
}
}
}
}
func prepareToUpdate() {
self.selectedUnit = self.material.unit
}
}
Then, below, add your MaterialPickerView
, as shown:
Disclaimer: You need to be able to access your API()
from here, so move it or add it in this view. As I have seen that you are re-instanciating it everytime, maybe it is better that you store its instance with let api = API()
and then refer to it with api
, and even pass it to this view as such!
struct MaterialPickerView: View {
@Binding var selectedUnit: String
@Binding var material : Material
@State var idx: Int = 0
var body: some View {
let binding = Binding<Int>(
get: { self.idx },
set: {
self.idx = $0
self.selectedUnit = API().units[self.idx].name
self.material.unit = self.selectedUnit
})
return Picker(selection: binding, label: Text("Einheit")) {
ForEach(API().units.indices) { i in
Text(API().units[i].name).tag(API().units[i].name)
}
}
}
}
That should do,let me know if it works!
Upvotes: 1