我遇到了下拉刷新和导航栏的问题。 问题是刷新完成后导航标题会跳回顶部(用户实际上没有释放拉动来刷新)。
可以避免吗?不记得 UIKit 有过这个问题。
发生的事情是这样的:
这是我处理数据刷新的 ViewModel 代码:
@Published var alerts: [Alert] = []
....
func refresh() async {
do {
let result = try await repository.fetchAlerts(page: 1, perPage: 20)
alerts = result.items
} catch {
showErrorBanner(error)
}
}
查看:
struct AlertsView: View {
@StateObject private var viewModel = AlertsViewModel()
@StateObject private var navigationManager = NavigationManager<AppRoutes>()
var body: some View {
NavigationStack(path: $navigationManager.path) {
ScrollView {
LazyVStack(alignment: .leading) {
ForEach(viewModel.alerts) { alert in
Text(alert.body)
}
}
}
.refreshable {
await viewModel.refresh()
}
.navigationTitle("Alerts")
.navigationBarTitleDisplayMode(.large)
}
.environmentObject(navigationManager)
}
}
我想也许这只是我的前端代码弄乱了它,但即使使用简单的布局(没有任何样式)也会发生这种情况:NavigationStack - ScrollView - LazyVStack - ForEach - Text。
编辑:此问题仅在
navigationBarTitleDisplayMode
设置为 .large
时发生。 .inline
工作正常...
最小。部署目标设置为 iOS16。
我在拉动刷新方面遇到了问题(因为我有一个自定义标头),并且能够找到一个效果非常好的自定义拉动刷新。认为这可能是 SwiftUI 可刷新修改器中的一个故障。
import SwiftUI
struct PullToRefresh: View {
var coordinateSpaceName: String
var onRefresh: ()->Void
@State var needRefresh: Bool = false
var body: some View {
GeometryReader { geo in
if (geo.frame(in: .named(coordinateSpaceName)).midY > 50) {
Spacer()
.onAppear {
needRefresh = true
}
} else if (geo.frame(in: .named(coordinateSpaceName)).maxY < 10) {
Spacer()
.onAppear {
if needRefresh {
needRefresh = false
onRefresh()
}
}
}
HStack {
Spacer()
if needRefresh {
ProgressView()
}
// You can uncomment this if you want to see where this is occurring in your View
// else {
// Text("⬇️")
// }
Spacer()
}
}.padding(.top, -50)
}
}
我通过添加 .coordinateSpace(name: "pullToRefresh") 将其添加到我的代码中,然后在我的 ScrollView 中插入自定义 PullToRefresh
PullToRefresh(coordinateSpaceName: "pullToRefresh") {
// These functions are the ones I want my viewModel to execute. For example, I want to shuffle the images that appear on the home page when the page is refreshed.
viewModel.styles.shuffle()
viewModel.posts.shuffle()
viewModel.brands.shuffle()
}