SwiftUI中如何将带头部的List滚动至最顶端?
SwiftUI List 滚动至真正顶端(含Section Header)
问题原因
当前代码滚动到第一个列表项的.top锚点,仅会将该项顶部对齐List可视区域顶部,但Section Header位于列表项上方,因此无法滚动到Header完全顶在最顶端的位置。
解决方案1:给Section Header添加ID直接滚动
给Section的Header视图分配一个唯一ID,调用scrollTo时直接滚动到这个ID并设置锚点为.top,就能让Header完全顶在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"), ] // 定义Header的唯一ID private let sectionHeaderID = UUID() var body: some View { NavigationStack { ScrollViewReader { proxy in List { Section { ForEach(items) { item in Text(item.title) .id(item.id) } } header: { Text("Header") .id(sectionHeaderID) // 给Header绑定ID } } .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Top") { withAnimation { proxy.scrollTo(sectionHeaderID, anchor: .top) // 滚动到Header的ID } } } } } } } }
解决方案2:添加隐藏的顶部锚点
如果不想修改Section Header,也可以在List最顶部添加一个高度为0的隐藏视图,给它分配ID,滚动到这个视图的.top,就能实现完全滚到顶端:
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"), ] private let topAnchorID = UUID() var body: some View { NavigationStack { ScrollViewReader { proxy in List { // 隐藏的顶部锚点视图,不占用可视空间 Color.clear .frame(height: 0) .id(topAnchorID) Section { ForEach(items) { item in Text(item.title) .id(item.id) } } header: { Text("Header") } } .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Top") { withAnimation { proxy.scrollTo(topAnchorID, anchor: .top) } } } } } } } }
说明
两种方案都能让List滚动到用户手指能触及的最顶端,完全贴合NavigationBar下方的位置,解决原代码仅滚动到第一个列表项顶部的问题。
内容的提问来源于stack exchange,提问作者erotsppa
相关产品推荐
相关产品推荐

