I have main ImportDataView with List of few pickers. Pickers are similar but I need to use different "selection". Each Picker is in separate var (some View) of ImportDataView extension. Is it possible to use one picker view instead of 3 (or more) and pass/bind different "selection" variable (from ImportDataViewModel)?
Thanks in advance.
import SwiftUI
class ImportDataViewModel: ObservableObject {
@Published var field1Index: Int?
@Published var field2Index: Int?
@Published var fieldNIndex: Int?
func getFieldNamesFromCSV() -> [String] {
return ["fieldFromFile1", "fieldFromFile2", "fieldFromFileN"]
}
}
struct ImportDataView: View {
@Environment(\.dismiss) var dismiss
@EnvironmentObject var itVM: ImportDataViewModel
var body: some View {
NavigationView {
List {
HStack {
Text("Field 1 *")
Spacer()
chooseField1View
}
HStack {
Text("Field 2 *")
Spacer()
chooseField2View
}
HStack {
Text("Field N *")
Spacer()
chooseFieldNView
}
}
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Back", role: .cancel) {
dismiss()
}
}
}
}
}
}
extension ImportDataView {
@ViewBuilder
private var chooseField1View: some View {
Picker(selection: $itVM.field1Index, label: EmptyView()) {
ForEach(itVM.getFieldNamesFromCSV().indices, id: \.self) { index in
Text(itVM.getFieldNamesFromCSV()[index]).tag(index as Int?)
}
}
}
@ViewBuilder
private var chooseField2View: some View {
Picker(selection: $itVM.field2Index, label: EmptyView()) {
ForEach(itVM.getFieldNamesFromCSV().indices, id: \.self) { index in
Text(itVM.getFieldNamesFromCSV()[index]).tag(index as Int?)
}
}
}
@ViewBuilder
private var chooseFieldNView: some View {
Picker(selection: $itVM.fieldNIndex, label: EmptyView()) {
ForEach(itVM.getFieldNamesFromCSV().indices, id: \.self) { index in
Text(itVM.getFieldNamesFromCSV()[index]).tag(index as Int?)
}
}
}
}
struct ImportDataView_Previews: PreviewProvider {
static var previews: some View {
ImportDataView()
.environmentObject(ImportDataViewModel())
.preferredColorScheme(.light)
}
}
I use separate "some View" variable for each Picker but understand that it is wrong way with copy/paste.
I expect to have only one "common" extension "some View" var and use it for all importing fields like this:
HStack {
Text("Field 1 *")
Spacer()
chooseFieldCommonView(selectionFieldIndex: $itVM.field1Index)
}
HStack {
Text("Field 2 *")
Spacer()
chooseFieldCommonView(selectionFieldIndex: $itVM.field2Index)
}
HStack {
Text("Field N *")
Spacer()
chooseFieldCommonView(selectionFieldIndex: $itVM.fieldNIndex)
}
Split the ChooseFieldView to a new file with input are index (which binds with view model outside) and string array as content
struct ChooseFieldView: View {
@Binding var index: Int
var values: [String]
var body: some View {
Picker(selection: $index, label: EmptyView()) {
ForEach(values.indices, id: \.self) { index in
Text(values[index]).tag(index)
}
}
}
}
Then in ImportDataView
edit like this:
struct ImportDataView: View {
@Environment(\.dismiss) var dismiss
@EnvironmentObject var itVM: ImportDataViewModel
var body: some View {
NavigationView {
List {
HStack {
Text("Field 1 *")
Spacer()
ChooseFieldView(index: $itVM.field1Index,
values: itVM.getFieldNamesFromCSV())
}
HStack {
Text("Field 2 *")
Spacer()
ChooseFieldView(index: $itVM.field2Index,
values: itVM.getFieldNamesFromCSV())
}
HStack {
Text("Field N *")
Spacer()
ChooseFieldView(index: $itVM.fieldNIndex,
values: itVM.getFieldNamesFromCSV())
}
}
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Back", role: .cancel) {
dismiss()
}
}
}
}
}
}
Result: