SwiftUI中传递数据的多维列表

时间:2020-05-31 13:57:51

标签: arrays swiftui swiftui-list

我有这个模型:

struct Training: Identifiable {
    let id = UUID()
    let name: String
    let workout: [Workout]?
}

和:

struct Workout: Identifiable {
    let id = UUID()
    let name: String
    let exercices: [Exercice]?
}

和:

struct Exercice: Identifiable {
    let id = UUID()
    let name: String
}

模型的数据来自环境对象。

该应用程序将启动,并显示一个空的培训列表,您可以在UI中添加培训。每个训练都有一个指向视图的导航链接,以将锻炼添加到每个训练中,并且在下一步中,您可以将锻炼添加到每个锻炼中。

按照我的逻辑,我使用上面显示的结构创建多维数组。

培训视图很简单:

struct TrainingsView: View {

    @EnvironmentObject var appState: AppState

    @State var showingDetail = false

    var body: some View {
        NavigationView {

            VStack {
                List {
                    ForEach (appState.trainings) { training in
                        NavigationLink(destination: WorkoutsView(training: training).environmentObject(self.appState)) {
                            Text(training.name)
                        }
                    }
                    .onDelete(perform: appState.removeTraining)
                }
                // Button to add trainings....
                .navigationBarTitle(Text("Trainings").foregroundColor(Color.white))
            }
        }
    }
}

WorkoutsView看起来一样,但是我在列出家长培训的项目时遇到了问题:

struct WorkoutsView: View {
    // ...
    var training: Training

    var body: some View {
        VStack {
            List {
                ForEach (appState.trainings(training).workouts) { workout in // I know the appState call is incorrect, but I don't know how to access is correctly.
                    NavigationLink(destination: ExercicesView(workout)) {
                        Text(workout.name)
                    }
                }
            }
            // ...
        }
    }
}

我已经尝试过:

List {
    ForEach (0 ..< appState.trainings.count) {
        NavigationLink(destination: WorkoutsView(training: $0).environmentObject(self.appState)) {
            Text(appState.trainings[$0].name)
        }
    }
}

我可以在appState.trainings[training].workouts中使用WorkoutsView,但是我在NavigationLink行上收到错误Contextual closure type '() -> Text' expects 0 arguments, but 1 was used in closure body,并且不知道该怎么办。

其他问题:如果这接近解决方案,我不需要该结构符合Identifiable吗?

1 个答案:

答案 0 :(得分:0)

根据您要设计系统的方式,这里有2种广泛的方法。

1。。您的子视图了解应用程序状态,并可以直接对其进行修改。因此,父级需要传递索引/关键字,以便孩子找到要修改的数据:

struct TrainingsView: View {
   @EnvironmentObject var appState: AppState

   var body: some View {
      NavigationView {
         List(0..<appState.trainings.count) { i in
            NavigationLink(destination: WorkoutsView(trainingIndex: i)) {
               Text(self.appState.trainings[i].name)
            }
         } 
      }
   }
}
struct WorkoutsView: View {
   var trainingIdx: Int
   @EnvironmentObject var appState: AppState

   var body: some View {
      VStack() {

         TextField("training name: ", text: $appState.trainings[trainingIdx].name)

         Button(action: {self.appState.trainings[trainingIdx].workouts.append(Workout(...))}) {
            Text("Add workout")
         }
      }
   }
}

2。。或者,您可能会说您不希望子视图了解应用程序的状态-您只希望他们修改一些静态struct,自己拥有(而是由其父母拥有),则应使用@Binding

下面的示例在概念上说明了这一点:

struct TrainingsView: View {
   @State var trainingA = Training(...)
   @State var trainingB = Training(...)

   var body: some Body {
      NavigationView {
         List {
            WorkoutsView(training: $trainingA)
            WorkoutsView(training: $trainingB)
         }
      }
   }
}
struct WorkoutsView: View {
   @Binding var training: Training

   var body: some View {
      VStack() {

         TextField("training name: ", text: $training.name)

         Button(action: { self.training.workouts.append(Workout(...)) }) {
            Text("Add workout")
         }
      }
   }
}