我正在尝试学习 SwiftUI 以及绑定(bind)的工作原理。
我有这段有效的代码,它显示了项目列表。当点击一个项目时,对该项目的绑定(bind)将传递到 subview :
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")
}
}
}
subview ,我在其中使用绑定(bind)改变项目:
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()
}
}
}
但是,我宁愿在不使用索引的情况下迭代项目数组(因为我想学习,并且它更易于阅读),但不确定如何将绑定(bind)传递到单个项目。我尝试了这样的操作,但是我无法访问 project.title
,因为它是一个绑定(bind),而不是一个字符串。
ForEach($state.projects) { project in
NavigationLink(destination: ProjectView(project: project)) {
Text(project.title)
}
}
我怎样才能实现这个目标?
最佳答案
注意:我使用的是 Xcode 11.2,其中 @ObjectBinding 已过时(因此您需要更新以验证以下代码)。
我询问了模型,因为它可能对方法很重要。对于类似的功能,我更喜欢合并的 ObservableObject,因此模型是引用而不是值类型。
这是我根据您的场景进行调整的方法。它不完全按照您的要求,因为 ForEach 需要一些序列,但您尝试使用不支持的类型提供它。
无论如何,您可以考虑将下面的内容作为替代(并且它没有索引)。它是完整的模块,因此您可以将其粘贴到 Xcode 11.2 中并在预览中进行测试。希望它能有所帮助。
预览:
解决方案:
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:如何迭代可绑定(bind)对象的数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57161893/