[英]SwiftUI weird List behavior when removing item from list
我的列表一直有问题,在删除项目后,它会被正确删除,但如果我在同一视图的两个分支之间切换,我的列表项目会得到这个奇怪的前导填充。
不确定如何准确解释它,所以我附上了发生的事情。
这是我的列表行代码:
if (/** condition **/) {
EmptyView()
} else {
ZStack(alignment: .center) {
NavigationLink(
destination: MovieDetailsView(movie: moviesVM.movie)) {
EmptyView()
}.opacity(0)
WebImage(url: moviesVM.movie.backdropUrl)
.resizable()
.placeholder {
Image("tile_placeholder")
.resizable()
.aspectRatio(aspectRatioW780Poster, contentMode: .fill)
.frame(maxHeight: 170)
.clipped()
}
.transition(.fade(duration: 0.5))
.aspectRatio(aspectRatioW780Poster, contentMode: .fill)
.frame(maxHeight: 170)
.clipped()
.overlay(TextOverlay(movieOrShow: moviesVM.movie))
}
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
// buttons that invoke removal
}
}
列表行在“配置文件”视图中实例化,如下所示:
NavigationView {
VStack {
if profileVM.profileRepository.profile == nil {
HStack(alignment: .center) {
Text("Please log in or sign up to use your watchlist. ☺️")
}
}
if profileVM.profileRepository.profile != nil {
HStack {
Text("Watched")
Toggle("Watched", isOn: $profileVM.defaultTab)
.onChange(of: profileVM.defaultTab, perform: { _ in
profileVM.updateDefaultTab()
})
.labelsHidden()
.tint(Constants.MUSH_BLUE)
Text("Watchlist")
}
// this is where my view "branches" depending on the toggle
HStack {
if !profileVM.defaultTab {
ZStack(alignment: .center) {
List {
ForEach(Array(profileVM.profileRepository.watchedMovies), id: \.id) { movie in
MovieListRow(moviesVM: MoviesViewModel(profileRepository: profileVM.profileRepository, movie: movie, fromProfile: true))
.id(movie.id)
.listRowInsets(EdgeInsets())
.listRowSeparator(.hidden)
}
}
.listStyle(InsetListStyle())
if profileVM.profileRepository.watchedMovies.count == 0 {
Text("Nothing here yet :)")
}
}
} else {
ZStack(alignment: .center) {
List {
ForEach(Array(profileVM.profileRepository.watchlistedMovies), id: \.id) { movie in
MovieListRow(moviesVM: MoviesViewModel(profileRepository: profileVM.profileRepository, movie: movie, fromProfile: true))
.id(movie.id)
.listRowInsets(EdgeInsets())
.listRowSeparator(.hidden)
}
}
.listStyle(InsetListStyle())
if profileVM.profileRepository.watchlistedMovies.count == 0 {
Text("Nothing here yet :)")
}
}
}
}
}
}
.navigationTitle("Watchlist")
}
这里有一些想法:
moviesVM
- 我们不在 SwiftUI 中使用视图 model 对象。对于瞬态视图数据,我们使用带有@State
和@Binding
的视图结构,这使得结构值类型实际上表现得像 object,因为当结构再次初始化时,它会自动具有与上次初始化时相同的属性值。 我们确实使用 object 来管理我们的 model 数据结构或 arrays 的生命周期,在我们使用environmentObject
传递给视图的ObservableObject
的@Published
属性中。ForEach(Array(
- ForEach
View 需要提供您的 model 数据才能正常工作,这通常是一个符合Identifiable
的结构数组。例如ForEach($model.movies) $movie in
我们想要写入访问权限时。MovieListRow(moviesVM MoviesViewModel(
- 像这样在body
中初始化对象是错误的,这会减慢 SwiftUI 并导致 memory 泄漏。在 body 中,我们只初始化超快速值类型的视图数据结构。body func 被反复调用,之后SwiftUI 已经区分并更新了屏幕上的标签等所有这些视图结构都被丢弃了。body
太大了,我们应该用少量的let
或@State
将它分解成小的视图。 这称为严格失效。 原因是 SwiftUI 具有依赖性和更改跟踪功能,如果正文太大,则效率不高。 命名结构可能会很棘手,因为它们是基于数据而不是屏幕区域,从ContentView1
、 ContentView2
等开始,直到您找到一个好的命名方案,例如一些基于属性的命名视图。推荐观看SwiftUI中的WWDC 2020 Data Essentials,学习正确使用SwiftUI。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.