我希望由一个具有子视图列表的母视图呈现一个可变字符串的动态数组,每个子视图均显示一个可编辑的字符串。同样,母视图将显示字符串的串联,每当在子视图中更新一个字符串时,这些字符串就会更新。
不能使用(1)ForEach(self.model.strings.indices)
自组索引可以改变的,并且不能使用(2)ForEach(self.model.strings) { string in
由于子视图想要编辑字符串,但string
将是不可改变的。
我发现进行这项工作的唯一方法是利用@EnvironmentObject
随参数一起传递的。这确实很笨拙,而且在进攻方面也很有限。
但是,我是swiftui的新手,我相信有更好的方法可以解决此问题,请告诉我们!
这是我现在所拥有的:
import SwiftUI
struct SimpleModel : Identifiable { var id = UUID(); var name: String }
let simpleData: [SimpleModel] = [SimpleModel(name: "text0"), SimpleModel(name: "text1")]
final class UserData: ObservableObject { @Published var simple = simpleData }
struct SimpleRowView: View {
@EnvironmentObject private var userData: UserData
var simple: SimpleModel
var simpleIndex: Int { userData.simple.firstIndex(where: { $0.id == simple.id })! }
var body: some View {
TextField("title", text: self.$userData.simple[simpleIndex].name)
}
}
struct SimpleView: View {
@EnvironmentObject private var userData: UserData
var body: some View {
let summary_binding = Binding<String>(
get: {
var arr: String = ""
self.userData.simple.forEach { sim in arr += sim.name }
return arr;
},
set: { _ = $0 }
)
return VStack() {
TextField("summary", text: summary_binding)
ForEach(userData.simple) { tmp in
SimpleRowView(simple: tmp).environmentObject(self.userData)
}
Button(action: { self.userData.simple.append(SimpleModel(name: "new text"))}) {
Text("Add text")
}
}
}
}
当EnironmentObject
被创建和传递SimpleView().environmentObject(UserData())
从AppDelegate中。
编辑:
作为参考,如果有人找到了,下面是@ pawello2222建议的使用ObservedObject而不是EnvironmentObject的完整解决方案:
import SwiftUI
class SimpleModel : ObservableObject, Identifiable {
let id = UUID(); @Published var name: String
init(name: String) { self.name = name }
}
class SimpleArrayModel : ObservableObject, Identifiable {
let id = UUID(); @Published var simpleArray: [SimpleModel]
init(simpleArray: [SimpleModel]) { self.simpleArray = simpleArray }
}
let simpleArrayData: SimpleArrayModel = SimpleArrayModel(simpleArray: [SimpleModel(name: "text0"), SimpleModel(name: "text1")])
struct SimpleRowView: View {
@ObservedObject var simple: SimpleModel
var body: some View {
TextField("title", text: $simple.name)
}
}
struct SimpleView: View {
@ObservedObject var simpleArrayModel: SimpleArrayModel
var body: some View {
let summary_binding = Binding<String>(
get: { return self.simpleArrayModel.simpleArray.reduce("") { $0 + $1.name } },
set: { _ = $0 }
)
return VStack() {
TextField("summary", text: summary_binding)
ForEach(simpleArrayModel.simpleArray) { simple in
SimpleRowView(simple: simple).onReceive(simple.objectWillChange) {_ in self.simpleArrayModel.objectWillChange.send()}
}
Button(action: { self.simpleArrayModel.simpleArray.append(SimpleModel(name: "new text"))}) {
Text("Add text")
}
}
}
}
您实际上并不需要@EnvironmentObject
(它将在您环境中的所有视图中全局可用)。
您可能要@ObservedObject
改用(或@StateObject
使用SwiftUI 2.0):
...
return VStack {
TextField("summary", text: summary_binding)
ForEach(userData.simple, id:\.id) { tmp in
SimpleRowView(userData: self.userData, simple: tmp) // <- pass userData to child views
}
Button(action: { self.userData.simple.append(SimpleModel(name: "new text")) }) {
Text("Add text")
}
}
struct SimpleRowView: View {
@ObservedObject var userData: UserData
var simple: SimpleModel
...
}
请注意,如果数据不是恒定的,则应使用动态ForEach
循环(带有显式id
参数):
ForEach(userData.simple, id:\.id) { ...
但是,当您和上SimpleModel
一堂课时,可以获得最佳结果ObservableObject
。这是一个更好的解决方案,如何正确执行:
另外,您可以简化summary_binding
使用reduce
:
let summary_binding = Binding<String>(
get: { self.userData.simple.reduce("") { $0 + $1.name } },
set: { _ = $0 }
)
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句