SwiftUI Strange/unexpected 删除 observedObjects 数组中的元素时的行为
SwiftUI Strange/unexpected behaviour when deleting elements in array of observedObjects
我正在尝试在我尝试开发的应用程序中创建可编辑的 'parts list'。走到这一步是一条艰难的道路 - 许多意想不到的障碍和障碍,现在已经克服了大部分(感谢 'krjw')。
所以,我现在处于可以将项目添加到具有可编辑字段的动态列表的阶段。删除某项后出现问题...无法编辑列表中的后续添加(等于删除的数量)。
为了方便起见,我将相关代码捆绑在一起如下:
import SwiftUI
// Thanks to KRJW on Whosebug for help getting this far...
struct PartEditView: View {
@ObservedObject var partToEdit:Part
var body: some View {
VStack{
HStack(alignment: .bottom){
TextField("Description", text: $partToEdit.description)
.frame(width: 350)
.padding(.all,5)
.cornerRadius(2)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.red, lineWidth: 1))
Spacer()
TextField("Price", text: $partToEdit.price).keyboardType(.decimalPad)
.frame(width: 80)
.padding(.all,5)
.cornerRadius(2)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.red, lineWidth: 1))
Spacer()
TextField("Quantity", text: $partToEdit.qty).keyboardType(.decimalPad)
.frame(width: 60)
.padding(.all,5)
.cornerRadius(2)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.red, lineWidth: 1))
Spacer()
VStack(alignment: .leading){
//Text("Line total").font(.caption).padding(.bottom,10)
Text(String(format: "%.2f", Double(partToEdit.linePrice)))
.frame(width:90,alignment: .leading)
.padding(.all,5)
.cornerRadius(4)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.blue, lineWidth: 1))
}
}
}
}
}
class Part: ObservableObject, Identifiable, Equatable {
static func == (lhs: Part, rhs: Part) -> Bool {
return lhs.id == rhs.id
}
//part line item (desc, price, qty, line price)
@Published var id: UUID
@Published var description:String
@Published var price:String
@Published var qty:String
var linePrice:Double{
let itemPrice = Double(price) ?? 0
let quantity = Double(qty) ?? 0
return itemPrice * quantity
}
init(id:UUID, description:String, price:String, qty:String) {
self.id = id
self.description = description
self.price = price
self.qty = qty
}
}
struct ContentView: View {
@State var parts = [Part]()
var body: some View {
VStack{
HStack{
Text("Add line ")
Image(systemName: "plus.circle").font(.largeTitle)
.onTapGesture {
let newPart:Part = Part(id: UUID(), description: "any.....thing", price: "", qty: "1")
self.parts.append(newPart)
}
}
List{
ForEach(parts){part in
PartEditView(partToEdit: part)
}.onDelete(perform: deleteRow)
}
HStack{
Spacer()
Text("Total: ")
Text(String(self.parts.reduce(0){[=11=] + .linePrice}))
}
Spacer()
}
}
func deleteRow(at offsets: IndexSet){
self.parts.remove(atOffsets: offsets)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
我怀疑数组索引以某种方式混淆了。
如果有人能对此有所了解,我将不胜感激。
该行似乎没有更新。我已经通过向具有所有 TextFields 的 PartEditView
HStack 添加一个 id 来解决它,如下所示:
struct PartEditView: View {
@ObservedObject var partToEdit:Part
var body: some View {
VStack{
HStack(alignment: .bottom){
TextField("Description", text: $partToEdit.description)
.frame(width: 350)
.padding(.all,5)
.cornerRadius(2)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.red, lineWidth: 1))
Spacer()
TextField("Price", text: $partToEdit.price).keyboardType(.decimalPad)
.frame(width: 80)
.padding(.all,5)
.cornerRadius(2)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.red, lineWidth: 1))
Spacer()
TextField("Quantity", text: $partToEdit.qty).keyboardType(.decimalPad)
.frame(width: 60)
.padding(.all,5)
.cornerRadius(2)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.red, lineWidth: 1))
Spacer()
VStack(alignment: .leading){
//Text("Line total").font(.caption).padding(.bottom,10)
Text(String(format: "%.2f", Double(partToEdit.linePrice)))
.frame(width:90,alignment: .leading)
.padding(.all,5)
.cornerRadius(4)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.blue, lineWidth: 1))
}
}
.id(partToEdit.id)
}
}
}
这样,行将针对每个 Part
进行更新。 SwiftUI 不会重新使用之前删除的行,而是会创建一个新行。
我正在尝试在我尝试开发的应用程序中创建可编辑的 'parts list'。走到这一步是一条艰难的道路 - 许多意想不到的障碍和障碍,现在已经克服了大部分(感谢 'krjw')。
所以,我现在处于可以将项目添加到具有可编辑字段的动态列表的阶段。删除某项后出现问题...无法编辑列表中的后续添加(等于删除的数量)。
为了方便起见,我将相关代码捆绑在一起如下:
import SwiftUI
// Thanks to KRJW on Whosebug for help getting this far...
struct PartEditView: View {
@ObservedObject var partToEdit:Part
var body: some View {
VStack{
HStack(alignment: .bottom){
TextField("Description", text: $partToEdit.description)
.frame(width: 350)
.padding(.all,5)
.cornerRadius(2)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.red, lineWidth: 1))
Spacer()
TextField("Price", text: $partToEdit.price).keyboardType(.decimalPad)
.frame(width: 80)
.padding(.all,5)
.cornerRadius(2)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.red, lineWidth: 1))
Spacer()
TextField("Quantity", text: $partToEdit.qty).keyboardType(.decimalPad)
.frame(width: 60)
.padding(.all,5)
.cornerRadius(2)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.red, lineWidth: 1))
Spacer()
VStack(alignment: .leading){
//Text("Line total").font(.caption).padding(.bottom,10)
Text(String(format: "%.2f", Double(partToEdit.linePrice)))
.frame(width:90,alignment: .leading)
.padding(.all,5)
.cornerRadius(4)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.blue, lineWidth: 1))
}
}
}
}
}
class Part: ObservableObject, Identifiable, Equatable {
static func == (lhs: Part, rhs: Part) -> Bool {
return lhs.id == rhs.id
}
//part line item (desc, price, qty, line price)
@Published var id: UUID
@Published var description:String
@Published var price:String
@Published var qty:String
var linePrice:Double{
let itemPrice = Double(price) ?? 0
let quantity = Double(qty) ?? 0
return itemPrice * quantity
}
init(id:UUID, description:String, price:String, qty:String) {
self.id = id
self.description = description
self.price = price
self.qty = qty
}
}
struct ContentView: View {
@State var parts = [Part]()
var body: some View {
VStack{
HStack{
Text("Add line ")
Image(systemName: "plus.circle").font(.largeTitle)
.onTapGesture {
let newPart:Part = Part(id: UUID(), description: "any.....thing", price: "", qty: "1")
self.parts.append(newPart)
}
}
List{
ForEach(parts){part in
PartEditView(partToEdit: part)
}.onDelete(perform: deleteRow)
}
HStack{
Spacer()
Text("Total: ")
Text(String(self.parts.reduce(0){[=11=] + .linePrice}))
}
Spacer()
}
}
func deleteRow(at offsets: IndexSet){
self.parts.remove(atOffsets: offsets)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
我怀疑数组索引以某种方式混淆了。
如果有人能对此有所了解,我将不胜感激。
该行似乎没有更新。我已经通过向具有所有 TextFields 的 PartEditView
HStack 添加一个 id 来解决它,如下所示:
struct PartEditView: View {
@ObservedObject var partToEdit:Part
var body: some View {
VStack{
HStack(alignment: .bottom){
TextField("Description", text: $partToEdit.description)
.frame(width: 350)
.padding(.all,5)
.cornerRadius(2)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.red, lineWidth: 1))
Spacer()
TextField("Price", text: $partToEdit.price).keyboardType(.decimalPad)
.frame(width: 80)
.padding(.all,5)
.cornerRadius(2)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.red, lineWidth: 1))
Spacer()
TextField("Quantity", text: $partToEdit.qty).keyboardType(.decimalPad)
.frame(width: 60)
.padding(.all,5)
.cornerRadius(2)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.red, lineWidth: 1))
Spacer()
VStack(alignment: .leading){
//Text("Line total").font(.caption).padding(.bottom,10)
Text(String(format: "%.2f", Double(partToEdit.linePrice)))
.frame(width:90,alignment: .leading)
.padding(.all,5)
.cornerRadius(4)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.blue, lineWidth: 1))
}
}
.id(partToEdit.id)
}
}
}
这样,行将针对每个 Part
进行更新。 SwiftUI 不会重新使用之前删除的行,而是会创建一个新行。