SwiftUI:如何遍历可绑定对象的数组? [英] SwiftUI: How to iterate over an array of bindable objects?
问题描述
我正在尝试学习SwiftUI,以及绑定如何工作.
I'm trying to learn SwiftUI, and how bindings work.
我有可以运行的代码,其中显示了项目列表.点击一个项目后,对该项目的绑定将传递给子视图:
I have this code that works, that shows a list of projects. When one project is tapped, a binding to that project is passed to the child view:
struct ProjectsView: View {
@ObjectBinding var state: AppState
@State var projectName: String = ""
var body: some View {
NavigationView {
List {
ForEach(0..<state.projects.count) { index in
NavigationLink(destination: ProjectView(project: self.$state.projects[index])) {
Text(self.state.projects[index].title)
}
}
}
.navigationBarTitle("Projects")
}
}
}
子视图,我在其中使用绑定对项目进行变异:
The child view, where I'm mutating the project using a binding:
struct ProjectView: View {
@Binding var project: Project
@State var projectName: String = ""
var body: some View {
VStack {
Text(project.title)
TextField(
$projectName,
placeholder: Text("Change project name"),
onCommit: {
self.project.title = self.projectName
self.projectName = ""
})
.padding()
}
}
}
但是,我宁愿在不使用索引的情况下遍历project数组(因为我想学习,并且更易于阅读),但是不确定如何将绑定传递给单个项目.我这样尝试过,但是后来我无法访问project.title
,因为它是绑定,而不是字符串.
However, I would rather iterate over the projects array without using indexes (beacuse I want to learn, and its easier to read), but not sure how I then can pass the binding to a single project. I tried it like this, but then I can't get access to project.title
, since it's a binding, and not a String.
ForEach($state.projects) { project in
NavigationLink(destination: ProjectView(project: project)) {
Text(project.title)
}
}
我该如何实现?
推荐答案
注意:我使用Xcode 11.2,@ ObjectBinding已被废弃(因此您需要更新以验证以下代码).
Note: I use Xcode 11.2, @ObjectBinding is obsoleted in it (so you need to update to verify below code).
我询问了模型,因为它对于方法可能很重要.对于类似的功能,我更喜欢Combine的ObservableObject,因此模型不是值类型的引用.
I asked about model, because it might matter for approach. For similar functionality I preferred Combine's ObservableObject, so model is reference not value types.
这是我针对您的情况进行调整的方法.它不完全符合您的要求,因为ForEach需要一些序列,但是您尝试使用不受支持的类型来填充它.
Here is the approach, which I tune for your scenario. It is not exactly as you requested, because ForEach requires some sequence, but you try to feed it with unsupported type.
无论如何,您可能会在下面将其视为替代项(它是无索引的).它是完整的模块,因此您可以将其粘贴到Xcode 11.2中并在预览中进行测试.希望这会有所帮助.
Anyway you may consider below just as alternate (and it is w/o indexes). It is complete module so you can paste it in Xcode 11.2 and test in preview. Hope it would be helpful somehow.
预览:
解决方案:
import SwiftUI
import Combine
class Project: ObservableObject, Identifiable {
var id: String = UUID().uuidString
@Published var title: String = ""
init (title: String) {
self.title = title
}
}
class AppState: ObservableObject {
@Published var projects: [Project] = []
init(_ projects: [Project]) {
self.projects = projects
}
}
struct ProjectView: View {
@ObservedObject var project: Project
@State var projectName: String = ""
var body: some View {
VStack {
Text(project.title)
TextField("Change project name",
text: $projectName,
onCommit: {
self.project.title = self.projectName
self.projectName = ""
})
.padding()
}
}
}
struct ContentView: View {
@ObservedObject var state: AppState = AppState([Project(title: "1"), Project(title: "2")])
@State private var refreshed = false
var body: some View {
NavigationView {
List {
ForEach(state.projects) { project in
NavigationLink(destination: ProjectView(project: project)) {
// !!! existance of .refreshed state property somewhere in ViewBuilder
// is important to inavidate view, so below is just a demo
Text("Named: \(self.refreshed ? project.title : project.title)")
}
.onReceive(project.$title) { _ in
self.refreshed.toggle()
}
}
}
.navigationBarTitle("Projects")
.navigationBarItems(trailing: Button(action: {
self.state.projects.append(Project(title: "Unknown"))
}) {
Text("New")
})
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
这篇关于SwiftUI:如何遍历可绑定对象的数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!