SwiftUI Странное / неожиданное поведение при удалении элементов в массиве наблюдаемых объектов - PullRequest
0 голосов
/ 12 февраля 2020

Я пытаюсь создать редактируемый «список деталей» в приложении, которое пытаюсь разработать. Это был тяжелый путь - далеко вперед - много неожиданных препятствий и препятствий, большинство из которых теперь преодолены (благодаря «krjw»).
Итак, я сейчас на этапе, когда предметы могут быть добавлены в динамику. c список с редактируемыми полями. Проблема возникает после удаления элемента ... последующие добавления в список (равные количеству удалений) редактировать нельзя. Для удобства я собрал соответствующий код вместе:

import SwiftUI

//  Thanks to KRJW on StackOverflow 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){$0 + $1.linePrice}))
            }
            Spacer()
        }
    }
    func deleteRow(at offsets: IndexSet){
        self.parts.remove(atOffsets: offsets)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Я подозреваю, что индексация массива как-то запуталась.
Если кто-нибудь сможет пролить свет на это, я очень признателен .

1 Ответ

0 голосов
/ 14 февраля 2020

Похоже, что строка не обновляется. Я решил это, добавив идентификатор к вашему PartEditView HStack, который имеет все TextFields, например:

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 не будет повторно использовать ранее удаленную строку, вместо этого будет создана новая.

...