每当我在列表滚动一点后点击列表中的导航链接时,列表似乎会暂时向下移动。请观看以下视频(启用“慢速动画”的模拟器):
这是我的代码:
struct SearchView: View {
private static let navTitle = "Title"
@EnvironmentObject var locModel: LocationViewModel
@ObservedObject private var searchModel = SearchViewModel()
var body: some View {
NavigationStack {
if searchModel.isLoading {
ProgressView()
.navigationTitle(SearchView.navTitle)
} else if searchModel.results.isEmpty {
Text("No results.") // TODO
.navigationTitle(SearchView.navTitle)
} else if let total = searchModel.total, let lastPage = searchModel.lastLoadedPage {
List {
Section {
ForEach(searchModel.results.indices, id: \.self) { i in
SearchResultRow(searchModel.results[i]).id(i)
}
if searchModel.results.count < total {
HStack {
Spacer()
ProgressView()
Spacer()
}.task {
await load(page: lastPage + 1)
}
}
} header: {
if let locName = locModel.location?.name {
Text("**\(total)** results near **\(locName)**")
}
}
}
.navigationTitle(SearchView.navTitle)
}
}
.onAppear {
Task.detached { await load() }
}
.onChange(of: locModel) {
Task.detached { await load() }
}
}
private func load(page: Int = 1) async {
if let loc = locModel.location {
await searchModel.load(location: loc, page: page)
}
}
}
struct MinyanSearchResultRow: View {
let searchResult: SearchResult
init(_ searchResult: SearchResult) {
self.searchResult = searchResult
}
var body: some View {
NavigationLink {
DetailView(searchResult: searchResult)
} label: {
VStack(alignment: .leading) {
Text("Hello there")
}
}
}
}
struct DetailView: View {
let searchResult: SearchResult
var body: some View {
Text("Test")
}
}
很多错误:不应该使用视图模型对象,而是使用
View
。等待的异步函数应该返回一些不是空的东西,通常存储在@State
中。像这样初始化一个 @ObservedObject
是内存泄漏,没有所有权。对于许多 if
来说效率很低,相反,定义一次 View
并在参数上使用 bool 逻辑(或将逻辑重构为计算得出的 var)。 onAppear
与 Task.detached
看起来像是一个错误,在 SwiftUI 中使用 async/await 是 .task
/.task(id:)
。最严重的会崩溃的错误是ForEach
是需要提供View
数据的Identifiable
,它不是for循环,所以改变:
ForEach(searchModel.results.indices, id: \.self) { i in
SearchResultRow(searchModel.results[i]).id(i) // this [i] will crash if the results change in size.
}
到
ForEach(searchModel.results) { result in
SearchResultRow(result) // this [i] will crash if the results change in size.
}
...
struct SearchResult: Identifiable {
...
希望所有这些建议都能有所帮助!