在典型列表中管理 SwiftUI 状态 - >详细信息应用



我正在构建一个结构与Apple教程相似的应用程序。我的应用程序有一个ListView,它可以导航到DetailsViewDetailsViewUIKit自定义UIView组成,我用UIViewRepresentable将其封装。到目前为止,一切都很好。

现在我有一个列表(比如说,地址(,我在内存中实例化,最终用核心数据替换。我能够(使用@EnvironmentObject(将List<Address>绑定到ListView

我陷入困境的地方是为每个DetailsView绑定元素。上面提到的苹果教程做了一些我认为不太好的事情——出于某种原因(我不知道(,它是:

  1. List绑定到详细信息视图(使用@EnvironmentObject(
  2. 将元素(在Apple教程案例中为landmark,在我的案例中为address(传递到详细信息视图
  3. 在响应于用户手势的更新期间,它有效地在List中搜索元素,以更新列表中的元素。这似乎很昂贵,尤其是在清单很大的情况下

这是#3的代码,对我来说是可疑的:

Button(action: {
self.userData.landmarks[self.landmarkIndex].isFavorite.toggle()
}) 

在他们的代码中,self.landmarkIndex进行线性搜索:

var landmarkIndex: Int {
userData.landmarks.firstIndex(where: { $0.id == landmark.id })!
}

我试图做的是将元素直接绑定到DetailsView,并让对元素的更新更新列表。到目前为止,我一直无法做到这一点。

有人知道正确的路吗?教程指向的方向似乎没有缩放。

您可以传递Binding<Landmark>,而不是传递Landmark对象。

LandmarkList.swift:将迭代从userData.landmark更改为它们的索引,以便获得绑定。然后将竞价传递到LandmarkDetailLandmarkRow

struct LandmarkList: View {
@EnvironmentObject private var userData: UserData
var body: some View {
NavigationView {
List {
Toggle(isOn: $userData.showFavoritesOnly) {
Text("Show Favorites Only")
}
ForEach(userData.landmarks.indices) { index in
if !self.userData.showFavoritesOnly || self.userData.landmarks[index].isFavorite {
NavigationLink(
destination: LandmarkDetail(landmark: self.$userData.landmarks[index])
.environmentObject(self.userData)
) {
LandmarkRow(landmark: self.$userData.landmarks[index])
}
}
}
}
.navigationBarTitle(Text("Landmarks"))
}
}
}

LandmarkDetail.swift:将landmark更改为Binding<Landmark>,并根据绑定切换收藏夹

@Binding var landmark: Landmark
.
.
.
Button(action: {
self.landmark.isFavorite.toggle()
}) {
if self.landmark
.isFavorite {
Image(systemName: "star.fill")
.foregroundColor(Color.yellow)
} else {
Image(systemName: "star")
.foregroundColor(Color.gray)
}
}

LandmarkRow.swift:将地标更改为Binding

@Binding var landmark: Landmark

以下是直接使用绑定对Address项目进行建模的方法示例

假设存在类似的视图模型,其中AddressIdentifiable结构

class AddressViewModel: ObservableObject {
@Published var addresses: [Address] = []
}

因此,在ListView中的某个地方,您可以使用以下

ForEach (Array(vm.addresses.enumerated()), id: .element.id) { (i, address) in
NavigationLink("(address.title)", 
destination: DetailsView(address: self.$vm.addresses[i])) // pass binding !!
}

相关内容

最新更新