SwiftUI:如何更新导航视图详细信息屏幕



我有一个应用程序,它可以从REST后端服务器获取车辆列表。然后,它使用该列表来构建一个车辆列表,可以点击该列表来显示其中一个车辆的详细信息:

@State private var selectedVehicle: Vehicle?
@Binding var vehicles: [Vehicle]
List {
NavigationView {
ForEach( vehicles ) { vehicle in
NavigationLink( destination: VehicleDetailScreen( vehicle: vehicle ),
tag: vehicle,
selection: self.$selectedVehicle ) {
Text( vehicle.name )
}
}
}
}
struct VehicleDetailScreen: View {    
var vehicle: Vehicle
var body: some View {
// Lots of rendering code omitted
}
}

到目前为止,一切都很好。这很好用。当我们从服务器获取更新信息时,问题就出现了。更新绑定的vehicles属性对于更新列表非常有效。但详细信息屏幕仍然显示不再相关的数据。

我的第一个想法是从NavigationView中弹出详细视图。不幸的是,SwiftUI没有提供任何可靠的方法,我可以在iPad上的两列视图中找到。

我的下一个想法是,我们也需要将车辆作为@Binding传递到VehicleDetailScreen,这样我们就可以更新它。但这也很难做到,因为我们需要对该绑定的引用,这样我们才能将更新的值填充到其中。我能想到的唯一方法是完全修改我们的网络和模型对象代码,使其像CoreData一样工作,将对象保存在内存中并使用服务器中的新值更新它们,而不是生成新对象。这将是一项巨大的努力,如果有其他选择的话,我显然不想这么做。

所以我有点拘泥于此。欢迎有任何想法/想法/建议!

也许@Binding的概念有些令人困惑。从@State var(父视图(到@Binding var(子视图(。一个struct散列,用于促进和重新排序数组[Vehicle]的元素。

类似这样的东西:

struct Vehicle: Hashable {
var name:String
//var otherItem: Any
}
struct ContentView: View {
@State var vehicle: Vehicle //the struct of your REST
@State var vehicles: [Vehicle] // the array of your REST
var body: some View {
List {
NavigationView {
ForEach(vehicles, id:.self) { item in // loop the array to get every single item conform to the struct
NavigationLink( destination: VehicleDetailScreen(vehicle: self.$vehicle)) { // here to pass the binding
Text("(self.vehicle.name)")
}
}
}
}
}
}
//detail view
struct VehicleDetailScreen: View {
@Binding var vehicle: Vehicle // here the binding
var body: some View {
Text("(vehicle.name)")
}
}

如果希望在数据更改时更新详细信息视图,则必须使用绑定。

就体系结构而言,我建议创建所谓的Stores,它保存可以在多个视图中使用的数据。这与Stores的一些静态提供程序相结合,使您可以在任何地方轻松访问和修改数据,并使视图自动更新。

使用UIKit时,您可以手动刷新数据,例如调用reloadTable。在SwiftUI中,这并没有完成。你可以假设手动触发视图更新,但我建议不要这样做,因为这不是SwiftUI的初衷。

我修改了你的代码,以显示一个例子:

class StoreProvider {
static let carStore = CarStore()
}
class CarStore: ObservableObject {
@Published var vehicles: [Vehicle] = [Vehicle(id: "car01", name: "Porsche", year: 2016), Vehicle(id: "car02", name: "Lamborghini", year: 2002)]
}
struct Vehicle: Identifiable, Hashable {
let id: String
var name: String
var year: Int
}
struct CarOverview: View {
@ObservedObject var store = StoreProvider.carStore
@State var selectedVehicle: Vehicle?
var body: some View {
NavigationView {
List {
ForEach(store.vehicles.indices) { vehicleIndex in
NavigationLink(destination: VehicleDetailScreen(vehicle: self.$store.vehicles[vehicleIndex])) {
Text(self.store.vehicles[vehicleIndex].name)
}.onTapGesture {
self.selectedVehicle = self.store.vehicles[vehicleIndex]
}
}
}
}
}
}
struct VehicleDetailScreen: View {
@Binding var vehicle: Vehicle
func updateValues() {
vehicle.year = Int.random(in: 1990..<2020)
}
var body: some View {
VStack {
Text(vehicle.name)
Text("Year: ") + Text(vehicle.year.description)
}.onTapGesture(perform: updateValues)
}
}

最新更新