SwiftUI 6.0(iOS 18)ScrollView 全新的滚动位置(ScrollPosition)揭秘
概览
在只有方寸之间大小的手持设备上要想体面的向用户展示海量信息,滚动视图(ScrollView)无疑是绝佳的“东牀之选”。
在 SwiftUI 历史的长河中,总觉得苹果对于 ScrollView 视图功能的升级是在“挤牙膏”。这不,在本届最新 WWDC24 重磅打造的 SwiftUI 6.0 中就让我们来看看 ScrollView 又能挤出怎样的新花样吧?
在本篇博文中,您将学到如下精彩的内容:
- 概览
- 1. SwiftUI 6.0 之前的滚动世界
- 2. SwiftUI 6.0(iOS 18)中全新的 ScrollPosition 类型
- 3. “新老搭配,干活不累”
- 4. 如何判断当前滚动是由用户指尖触发的?
- 5. 实时监听滚动视图的内容偏移(ContentOffset)
- 总结
在 WWDC24 里,苹果对 SwiftUI 6.0 中滚动视图的全新升级无疑解了一众秃头码农们的额燃眉之急。
那还等什么呢?让我们马上开始滚动大冒险吧!
Let‘s rolling!!!😉
1. SwiftUI 6.0 之前的滚动世界
苹果从 SwiftUI 2.0 开始陆续“发力”向 ScrollView 增加了许多新特性,其中包括秃头码农们翘首跂踵的滚动位置读取与设置、滚动模式等高级功能。
在 SwiftUI 6.0 之前,我们是通过单一状态来读取和设置滚动位置的:
struct ContentView: View { @State private var position: Int? var body: some View { ScrollView { LazyVStack { ForEach(0.. index in Text(verbatim: index.formatted()) .id(index) } } .scrollTargetLayout() } .scrollTargetBehavior(.viewAligned) .scrollPosition(id: $position) } } @State private var position = ScrollPosition(edge: .top) var body: some View { ScrollView { Button("Scroll to bottom") { position.scrollTo(edge: .bottom) } ForEach(1.. index in Text(verbatim: index.formatted()) .id(index) } Button("Scroll to top") { position.scrollTo(edge: .top) } } .scrollPosition($position) } } @State private var position = ScrollPosition(edge: .top) var body: some View { ScrollView { Button("Random Scroll") { let id = (1.. index in Text(verbatim: index.formatted()) .id(index) } } .scrollPosition($position) .animation(.default, value: position) } } @State private var position = ScrollPosition(edge: .top) var body: some View { ScrollView { Button("Scroll to offset") { position.scrollTo(point: CGPoint(x: 0, y: 100)) } ForEach(1.. index in Text(verbatim: index.formatted()) .id(index) } } .scrollPosition($position) .animation(.default, value: position) } } position.scrollTo(y: 100) position.scrollTo(x: 200) } @State private var position = ScrollPosition(edge: .top) @State var curPosID: Int? @State var offsetY: CGFloat? var body: some View { ScrollView { ForEach(1.. index in Text(verbatim: index.formatted()) .font(.largeTitle.weight(.heavy)) .padding() .id(index) } .scrollTargetLayout() } .scrollPosition(id: $curPosID) .scrollPosition($position) .animation(.default, value: position) .safeAreaInset(edge: .bottom) { Button("Random Scroll") { let id = (1.. old,new in print("用代码滚动视图的ID: \(new.viewID)") curPosID = new.viewID as? Int } .onChange(of: curPosID) { _,new in print("实时滚动视图的 ID: \(new)") } } } @State private var position = ScrollPosition(edge: .top) var body: some View { ScrollView { ForEach(1.. index in Text(verbatim: index.formatted()) .font(.largeTitle.weight(.heavy)) .padding() .id(index) } } .scrollPosition($position) .animation(.default, value: position) .safeAreaInset(edge: .bottom) { Button("Random Scroll") { let id = (1.. old,new in print("是否由用户拖动引起的滚动:\(new.isPositionedByUser ? "是" : "否")") } } } old,new in print("当前内容滚动偏移:\(new.point)") } @State private var position = ScrollPosition(edge: .top) @State var curPosID: Int? @State var offsetY: CGFloat? var body: some View { ScrollView { ForEach(1.. index in Text(verbatim: index.formatted()) .font(.largeTitle.weight(.heavy)) .padding() .id(index) } .scrollTargetLayout() } .scrollPosition(id: $curPosID) .scrollPosition($position) .animation(.default, value: position) .safeAreaInset(edge: .bottom) { Button("Random Scroll") { let id = (1.. old,new in print("用代码滚动视图的ID: \(new.viewID)") curPosID = new.viewID as? Int } .onChange(of: curPosID) { _,new in print("实时滚动视图的 ID: \(new)") } .onScrollGeometryChange(for: CGFloat.self, of: { geo in geo.contentOffset.y }, action: { old, new in offsetY = new }) .onChange(of: offsetY) { _, new in guard let new else { return } print("当前 y 轴滚动偏移:\(new.formatted())") } } }
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!


