swiftui - 在 SwiftUI 的 ForEach 中保持实例的唯一性
问题描述
我有一个包含 ForEach 的视图,并且我有一个向列表添加更多项目的按钮。在每个实例中,在循环中,我都有一个预先填充有自动生成的计数器名称的 TextField。但是当我添加一个新实例时,所有以前添加的项目都将名称更改为相同的名称:
我想要的是将计数器名称设置为第一个计数器 1、第二个计数器 2、第三个计数器 3 等。
这是我的代码:
import SwiftUI
struct Counter: Identifiable, Equatable {
var id: UUID = UUID()
var name: String = ""
var rows: Int = 0
var repeats: Int?
var rowsPerRepeat: Int?
var countRepeats: Bool = false
}
struct Project: Identifiable, Equatable {
var id:UUID = UUID()
var name:String = ""
var counters: [Counter] = [Counter]()
}
class AddEditCounterViewModel : ObservableObject {
@Published var counter : Counter
@Published var project: Project
init(counter: Counter, project: Project) {
self.project = project
self.counter = counter
if self.counter.name.isEmpty {
self.counter.name = counterNameGenerator()
}
}
func counterNameGenerator() -> String {
let count = project.counters.count
return String.localizedStringWithFormat(NSLocalizedString("Counter %d", comment: "Counter name"), count)
}
func countRepeats(countRepeats : Bool) {
if countRepeats {
counter.countRepeats = true
if counter.rowsPerRepeat == nil {
counter.rowsPerRepeat = 2
}
} else {
counter.countRepeats = false
counter.rowsPerRepeat = nil
}
}
}
struct AddEditCounterView: View {
@ObservedObject var viewModel : AddEditCounterViewModel
@State var countRepeats = false
@State var hiddenHeight : CGFloat = 0.0
@State var opacity = 0.0
init(viewModel: AddEditCounterViewModel) {
self.viewModel = viewModel
}
var body: some View {
VStack(spacing: 20) {
VStack (alignment: .leading) {
Text("Counter Name")
.multilineTextAlignment(.leading)
TextField("", text: $viewModel.counter.name)
}
HStack {
Text("Start at")
.multilineTextAlignment(.leading)
Spacer()
TextField("", value: $viewModel.counter.rows, formatter: NumberFormatter())
.keyboardType(.numberPad)
.multilineTextAlignment(.center)
.frame(width: 70.0, height: nil, alignment: .leading)
}.frame(maxWidth: .infinity, alignment: .leading)
Toggle(isOn: $countRepeats) {
Text("Count sets (repeats)")
}.onChange(of: countRepeats, perform: { value in
viewModel.countRepeats(countRepeats: value)
hiddenHeight = value ? 30.0 : 0
opacity = value ? 1 : 0
})
HStack {
Text("How many rows per set (repeat)")
.multilineTextAlignment(.leading)
Spacer()
TextField("", value: $viewModel.counter.rowsPerRepeat, formatter: NumberFormatter())
.keyboardType(.numberPad)
.multilineTextAlignment(.center)
.frame(width: 70.0, height: nil, alignment: .leading)
}
.opacity(opacity)
.frame(maxWidth: .infinity, maxHeight: $hiddenHeight.wrappedValue, alignment: .leading)
.animation(.easeIn)
}
}
}
class AddEditProjectViewModel: ObservableObject {
@Published var project : Project
init(project: Project) {
self.project = project
if self.project.counters.count < 1 {
addNewCounter()
}
}
func addNewCounter() {
project.counters.append(Counter())
}
}
struct AddEditProjectView: View {
@ObservedObject var viewModel : AddEditProjectViewModel
var body: some View {
VStack {
ForEach(viewModel.project.counters) { counter in
AddEditCounterView(viewModel: AddEditCounterViewModel(counter: viewModel.project.counters[0], project: viewModel.project))
}
Button( action: {
viewModel.addNewCounter()
}){
Text("Add Counter")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
AddEditProjectView(viewModel: AddEditProjectViewModel(project: Project()))
}
}
解决方案
推荐阅读
- reactjs - 是否可以在 Interface 中定义 render-prop 返回值的 jsx 树?
- python - Python:SettingWithCopyWarning
- c++ - 复制构造函数的参数
- jenkins - 带有groovy中地图列表的Jenkins管道选择输入不起作用
- ios - 使用 UITableView 进行双重输入
- c# - 无法通过 EF Core 找到 Oracle 表
- c# - 将数据从数据库导出到 Excel 并对列求和?
- datastax - 卡桑德拉名单
没有使用 datastax java driver 4.0.0 反序列化 - javascript - 为什么我在道具更改后得到旧的状态值
- android - 如何避免 FragmentManager 重新创建片段?