如何在SwiftUI中把列表滚动到最顶部?
我尝试了各种技巧,但仍无法在SwiftUI中带有头部的列表滚动到最顶端的位置。下面给出一个最小可复现示例(MRE)。它能滚动到大致的顶部位置,但并不是用户通过手指滑动能达到的真正最顶端的位置。
我不想使用ScrollView或其他东西。我其实需要的是List。
struct StackScrollToTopExample: View {
private struct ExampleItem: Identifiable {
let id = UUID()
let title: String
}
private let items = [
ExampleItem(title: "Passport"),
ExampleItem(title: "Wallet"),
ExampleItem(title: "Phone charger"),
ExampleItem(title: "Headphones"),
ExampleItem(title: "Sunglasses"),
ExampleItem(title: "Toothbrush"),
ExampleItem(title: "Toothpaste"),
ExampleItem(title: "Socks"),
ExampleItem(title: "T-shirt"),
ExampleItem(title: "Jeans"),
ExampleItem(title: "Jacket"),
ExampleItem(title: "Book"),
ExampleItem(title: "Camera"),
ExampleItem(title: "Medication"),
ExampleItem(title: "Water bottle"),
ExampleItem(title: "Travel adapter"),
ExampleItem(title: "Umbrella"),
ExampleItem(title: "Notebook"),
ExampleItem(title: "Snacks"),
ExampleItem(title: "Keys"),
]
var body: some View {
NavigationStack {
ScrollViewReader { proxy in
List {
Section {
ForEach(items) { item in
Text(item.title)
.id(item.id)
}
} header: {
Text("Header")
}
}
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button("Top") {
guard let firstItemID = items.first?.id else { return }
withAnimation {
proxy.scrollTo(firstItemID, anchor: .top)
}
}
}
}
}
}
}
}
解决方案
之所以它不会自动把列表一直滚回到起始位置,是因为列表分区有一个头部。因此第一行的起始位置实际上位于 .top 之下。如果你用锚点 .top 滚动到第一行,列表会向上滚动一点。
为了解决,我建议给头部设置一个id,然后滚动到这个目标。然而,我发现使用锚点 .top 时这仍然不太可靠。把锚点改为 .center 会更可靠:
private let headerId = "HEADER"
List {
Section {
ForEach(items) { item in
Text(item.title)
// .id(item.id) 👈 not needed
}
} header: {
Text("Header")
.id(headerId) // 👈 id added
}
}
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button("Top") {
withAnimation {
proxy.scrollTo(headerId, anchor: .center) // 👈 updated
}
}
}
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。