SwiftUI:更新变量时 NavigationLink 弹出

SwiftUI: NavigationLink pops back when variable is updated

我遇到了这个问题,当更新变量时,导航 link 弹出。这有点令人困惑,因为这种行为不会发生在应用程序的其他地方,但我正在做同样的事情。

首先,有一个符合 Identifiable 的 Vehicle 结构。在内容视图中,它显示在滚动视图的 NavigationView 中。

ScrollView(showsIndicators: false) {
            VStack {
                ForEach(user.vehicles) { vehicle in
                    VehicleListItem(user: $user,
                                    vehicle: vehicle)

                }
            }
        }

该列表项有一个导航 link,可将用户带到不同的视图。车辆作为绑定传递到下一个视图。

NavigationLink(destination: {
                VehicleView(user: $user,
                            vehicle: $user.vehicles[user.vehicles.firstIndex(where: {[=11=].id == vehicle.id})!],
                            make: vehicle.make,
                            model: vehicle.model,
                            year: vehicle.year
                )
            }, label: {
                Image(systemName: "car")
                    .font(.system(size: 100))
            }).padding(.bottom, 20)

在车辆视图中,用户可以编辑车辆信息(制造商、型号、年份)并且工作正常。当用户对 Vehicle 进行更改时,它不会弹回到之前的视图。

Section() {
            VehicleHandler(make: $make, model: $model, year: $year)
            
            Button(action: {
                //Update
                vehicle.make = make
                vehicle.model = model
                vehicle.year = year
                
            }, label: {
                ButtonView(label: "Update")
            }).disabled(make.isEmpty ||
                        model.isEmpty ||
                        (make == vehicle.make && model == vehicle.model && year == vehicle.year))
        }

车辆处理程序

struct VehicleHandler: View {

enum Field: Hashable {
    case make
    case model
}

@FocusState private var field: Field?

@Binding var make: String
@Binding var model: String
@Binding var year: Int //Set to current year

var body: some View {
    TextField("Make", text: $make)
        .submitLabel(.next)
        .focused($field, equals: .make)
        .onSubmit {
            field = .model
        }
    
    TextField("Model", text: $model)
        .submitLabel(.done)
        .focused($field, equals: .model)

    
    Picker("Year", selection: $year, content: {
        ForEach((1900...Date().year()).reversed(), id: \.self) { year in
            Text(String(year))
                .tag(year as Int)
        }

    })
}

}

现在,用户可以添加维护记录。一旦他们添加了一条记录,它就会使用 ForEach 显示。记录也符合可识别的。

//Only show 5
            ForEach(vehicle.maintenanceRecords.prefix(5)) { record in
                NavigationLink(destination: {
                    MaintenanceView(user: $user,
                                    record: $vehicle.maintenanceRecords[vehicle.getMaintenanceIndex(id: record.id)],
                                    date: record.date,
                                    mileage: record.mileage ?? 0,
                                    note: record.note,
                                    cost: record.cost ?? 0,
                                    tasks: record.tasks)
                }, label: {
                    Text("\(record.date.formattedNoYear()) - \(record.note)")
                })
            }

相同的概念被用于编辑维护记录。记录作为绑定传递,传递记录信息以更新各个字段。当用户按下更新时,它会更新记录。正是在这一点上,只要您进行编辑并按更新,它就会弹出回 VehicleView。当我不使用 ID 时,我曾经遇到过这个问题,但是,每个结构都符合 Identifiable 并且 ID 没有被修改。我已经检查以确保它们保持不变,其中包括车辆 ID 和记录。有谁知道为什么它不断地回到这里,但在更新车辆信息时却没有?如果您需要更多信息,请告诉我。

            RecordHandler(user: $user,
                      date: $date,
                      mileage: $mileage,
                      note: $note,
                      cost: $cost,
                      task: $task,
                      tasks: $tasks)
        
        Section() {
            Button(action: {
                
                //Update record
                record.date = date
                record.note = note
                record.tasks = tasks
                
                if mileage.isZero == false {
                    record.mileage = mileage
                }
                
                if cost.isZero == false {
                    record.cost = cost
                }
                
                //Clear task
                task = ""
            }, label: {
                ButtonView(label: "Update")
            }).disabled(note.isEmpty ||
                        (date == record.date && mileage == record.mileage && note == record.note && cost == record.cost && tasks == record.tasks)
            )
        }

记录处理程序

struct RecordHandler: View {

enum Field: Hashable {
    case note
    case mileage
    case cost
    case task
}

@FocusState var field: Field?

@Binding var user: User
@Binding var date: Date
@Binding var mileage: Float
@Binding var note: String
@Binding var cost: Float
@Binding var task: String
@Binding var tasks: [Vehicle.Record.Task]

@State var suggestion: String = ""

var body: some View {
    Section() {
        DatePicker("Date", selection: $date)
        TextField("Note", text: $note)
            .submitLabel(.next)
            .focused($field, equals: .note)
            .onSubmit {
                field = .mileage
            }
        FieldWithLabel(label: "Mileage", value: $mileage, formatter: NumberFormatter.number)
            .submitLabel(.next)
            .focused($field, equals: .mileage)
            .onSubmit {
                field = .cost
            }
        FieldWithLabel(label: "Cost", value: $cost, formatter: NumberFormatter.currency)
            .submitLabel(.next)
            .focused($field, equals: .cost)
            .onSubmit {
                field = .task
            }
    }
    
    //For task
    Section() {
        HStack {
            TextField("Task", text: $task)
                .submitLabel(.done)
                .focused($field, equals: .task)
                .onSubmit {
                    addTask()
                    field = .task
                }
                .toolbar(content: {
                    ToolbarItemGroup(placement: .keyboard) {
                        Spacer()

                        Button("Close") {
                            UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
                        }
                    }
                })
                .onChange(of: task, perform: { value in
                    //See if any of the saved task are similar
                    if user.tasks.contains(where: {[=16=].contains(value)}) {
                        //Set suggestion
                        suggestion = user.tasks.first(where: {[=16=].contains(value)})!
                    } else {
                        //Leave it empty if there's nothing
                        suggestion = ""
                    }
                })
            Spacer()
            
            Button(action: {
                addTask()
            }, label: {
                Image(systemName: "plus.circle.fill")
                    .font(.system(size: 22))
            }).buttonStyle(BorderlessButtonStyle())
            
        }
        
        //To show task suggestions
        if suggestion.isEmpty == false {
            Button(action: {
                //Set task to suggestion
                task = suggestion
                
                //Add task
                addTask()
                
                //Focus field
                field = .task
            }, label: {
                HStack {
                    Text("Suggestion")
                    Spacer()
                    Text(suggestion)
                }
            })
        }

        
        ForEach(tasks) { task in
            Text(task.name)
        }
        .onDelete(perform: delete)
    }

}

func addTask() {
    //Create
    let task = Vehicle.Record.Task(name: task)
    
    //Add to array
    tasks.append(task)
    
    //Clear
    self.task = ""
}

func delete(at offsets: IndexSet) {
    tasks.remove(atOffsets: offsets)
}

}

我遇到了同样的问题,今天成功解决了。尝试将选项 .navigationViewStyle(.stack) 添加到 NavigationView

struct ContentView: View {
    var body: some View {
        NavigationView {
            //All your content and navigation links
        }.navigationViewStyle(.stack)
    }
}