把握 SwiftUI 中的 ScrollView:滚动多少

打印 上一主题 下一主题

主题 1725|帖子 1725|积分 5185




  
媒介

本文探讨了如何利用 onScrollGeometryChange 视图修饰符有效地监控和管理滚动位置和多少。通过详细的代码示例息争释,你将学习如何利用这些工具创建动态和相应敏捷的用户界面。
SwiftUI 是一个强大的框架,它简化了在苹果平台上构建用户界面的过程。SwiftUI 中的一个基本组件是 ScrollView,它允许用户通过滚动导航内容。然而,管理滚动位置和理解滚动交互可能是一个挑战。ScrollGeometry 和 onScrollGeometryChange 视图修饰符的引入办理了这些挑战,为开发者提供了更多的控制和对滚动行为的深入了解。
什么是 ScrollPosition

ScrollPosition 是一种类型,允许开发者以编程方式读取或更改滚动位置。固然有效,但当用户利用手势与滚动视图交互时,它显得不够全面。以下是一个展示 ScrollPosition 利用的示例:
  1. struct ContentView: View {
  2.     @State private var position = ScrollPosition(edge: .top)
  3.    
  4.     var body: some View {
  5.         ScrollView {
  6.             Button("Scroll to offset") {
  7.                 position.scrollTo(point: CGPoint(x: 0, y: 100))
  8.             }
  9.             
  10.             ForEach(1..<100) { index in
  11.                 Text(verbatim: index.formatted())
  12.                     .id(index)
  13.             }
  14.         }
  15.         .scrollPosition($position)
  16.         .animation(.default, value: position)
  17.     }
  18. }
复制代码
在这个示例中,我们将滚动视图绑定到一个状态属性。当按下按钮时,滚动视图会将其内容偏移移动到指定点。然而,我们无法读取用户通过手势交互设置的详细内容偏移。
引入 ScrollGeometry

SwiftUI 的新 ScrollGeometry 类型以及 onScrollGeometryChange 视图修饰符提供了一个办理方案。这些工具允许开发者在用户交互期间准确读取内容偏移。
利用 onScrollGeometryChange

让我们探索如何利用 onScrollGeometryChange 视图修饰符与 ScrollGeometry:
  1. struct ContentView: View {
  2.     @State private var scrollPosition = ScrollPosition(y: 0)
  3.     @State private var offsetY: CGFloat = 0
  4.    
  5.     var body: some View {
  6.         ScrollView {
  7.             ForEach(1..<100, id: \.self) { number in
  8.                 Text(verbatim: number.formatted())
  9.                     .id(number)
  10.             }
  11.         }
  12.         .scrollPosition($scrollPosition)
  13.         .onScrollGeometryChange(for: CGFloat.self) { geometry in
  14.             geometry.contentOffset.y
  15.         } action: { oldValue, newValue in
  16.             if oldValue != newValue {
  17.                 offsetY = newValue
  18.             }
  19.         }
  20.         .onChange(of: offsetY) {
  21.             print(offsetY)
  22.         }
  23.     }
  24. }
复制代码
onScrollGeometryChange 视图修饰符接受三个参数:

  • 类型参数:指定要跟踪的滚动多少类型。在此示例中,我们利用 CGFloat 来跟踪内容偏移的 Y 轴。
  • 转换闭包:从 ScrollGeometry 实例中提取所需信息。
  • 动作闭包:处置惩罚滚动多少的变革,通过比较旧值和新值,允许我们相应地更新状态属性。
高级滚动多少跟踪

ScrollGeometry 提供了许多有代价的属性,如内容偏移、边界、容器大小、可见矩形、内容插入和内容大小。开发者可以提取单个属性或组合多个属性以获得全面的见解。
以下是一个结合内容大小和可见矩形跟踪的示例:
  1. struct ContentView: View {
  2.     struct ScrollData: Equatable {
  3.         let size: CGSize
  4.         let visible: CGRect
  5.     }
  6.    
  7.     @State private var scrollPosition = ScrollPosition(y: 0)
  8.     @State private var scrollData = ScrollData(size: .zero, visible: .zero)
  9.    
  10.     var body: some View {
  11.         ScrollView {
  12.             ForEach(1..<100, id: \.self) { number in
  13.                 Text(verbatim: number.formatted())
  14.                     .id(number)
  15.             }
  16.         }
  17.         .scrollPosition($scrollPosition)
  18.         .onScrollGeometryChange(for: ScrollData.self) { geometry in
  19.             ScrollData(size: geometry.contentSize, visible: geometry.visibleRect)
  20.         } action: { oldValue, newValue in
  21.             if oldValue != newValue {
  22.                 scrollData = newValue
  23.             }
  24.         }
  25.         .onChange(of: scrollData) {
  26.             print(scrollData)
  27.         }
  28.     }
  29. }
复制代码
在这个示例中,我们定义了一个 ScrollData 结构来保存大小和可见矩形属性。在利用 onScrollGeometryChange 视图修饰符时,我们将 ScrollData 作为转换闭包的返回类型,从 ScrollGeometry 实例中提取所有所需的数据。
完备代码示例分析

下面是一个完备的 SwiftUI Demo,其中包含了我们刚刚讨论的 ScrollView、ScrollGeometry 和 onScrollGeometryChange 的利用示例。你可以在 Xcode 中运行这个项目来观察其效果。
完备代码示例
  1. import SwiftUI
  2. struct ContentView: View {
  3.     @State private var scrollPosition = ScrollPosition(y: 0)
  4.     @State private var offsetY: CGFloat = 0
  5.    
  6.     var body: some View {
  7.         VStack {
  8.             Text("Scroll Offset: \(offsetY, specifier: "%.2f")")
  9.                 .padding()
  10.             
  11.             ScrollView {
  12.                 ForEach(1..<100, id: \.self) { number in
  13.                     Text(verbatim: number.formatted())
  14.                         .padding()
  15.                         .frame(maxWidth: .infinity)
  16.                         .background(Color(.secondarySystemBackground))
  17.                         .cornerRadius(8)
  18.                         .padding(.horizontal)
  19.                         .id(number)
  20.                 }
  21.             }
  22.             .scrollPosition($scrollPosition)
  23.             .onScrollGeometryChange(for: CGFloat.self) { geometry in
  24.                 geometry.contentOffset.y
  25.             } action: { oldValue, newValue in
  26.                 if oldValue != newValue {
  27.                     offsetY = newValue
  28.                 }
  29.             }
  30.             .onChange(of: offsetY) {
  31.                 print(offsetY)
  32.             }
  33.         }
  34.     }
  35. }
  36. struct ScrollData: Equatable {
  37.     let size: CGSize
  38.     let visible: CGRect
  39. }
  40. struct AdvancedContentView: View {
  41.     @State private var scrollPosition = ScrollPosition(y: 0)
  42.     @State private var scrollData = ScrollData(size: .zero, visible: .zero)
  43.    
  44.     var body: some View {
  45.         VStack {
  46.             Text("Content Size: \(scrollData.size.width, specifier: "%.2f") x \(scrollData.size.height, specifier: "%.2f")")
  47.                 .padding()
  48.             Text("Visible Rect: \(scrollData.visible.origin.x, specifier: "%.2f"), \(scrollData.visible.origin.y, specifier: "%.2f") - \(scrollData.visible.width, specifier: "%.2f") x \(scrollData.visible.height, specifier: "%.2f")")
  49.                 .padding()
  50.             
  51.             ScrollView {
  52.                 ForEach(1..<100, id: \.self) { number in
  53.                     Text(verbatim: number.formatted())
  54.                         .padding()
  55.                         .frame(maxWidth: .infinity)
  56.                         .background(Color(.secondarySystemBackground))
  57.                         .cornerRadius(8)
  58.                         .padding(.horizontal)
  59.                         .id(number)
  60.                 }
  61.             }
  62.             .scrollPosition($scrollPosition)
  63.             .onScrollGeometryChange(for: ScrollData.self) { geometry in
  64.                 ScrollData(size: geometry.contentSize, visible: geometry.visibleRect)
  65.             } action: { oldValue, newValue in
  66.                 if oldValue != newValue {
  67.                     scrollData = newValue
  68.                 }
  69.             }
  70.             .onChange(of: scrollData) {
  71.                 print(scrollData)
  72.             }
  73.         }
  74.     }
  75. }
  76. @main
  77. struct ScrollViewDemoApp: App {
  78.     var body: some Scene {
  79.         WindowGroup {
  80.             TabView {
  81.                 ContentView()
  82.                     .tabItem {
  83.                         Label("Basic", systemImage: "1.square.fill")
  84.                     }
  85.                
  86.                 AdvancedContentView()
  87.                     .tabItem {
  88.                         Label("Advanced", systemImage: "2.square.fill")
  89.                     }
  90.             }
  91.         }
  92.     }
  93. }
复制代码
如何运行

  • 打开 Xcode 并创建一个新的 SwiftUI 项目。
  • 将默认天生的 ContentView.swift 文件更换为上面的完备代码。
  • 在 @main 注释下的应用程序入口点中,确保你的主视图是 ScrollViewDemoApp。
  • 运行项目。
功能解释


  • ContentView: 展示基本的滚动偏移追踪功能,通过 onScrollGeometryChange 视图修饰符追踪 Y 轴的内容偏移。
  • AdvancedContentView: 展示更高级的滚动多少追踪功能,追踪内容大小和可见矩形的变革。
  • ScrollViewDemoApp: 包含 TabView,方便在基本和高级示例之间切换。
总结

今天,我们探讨了 SwiftUI 中的新 ScrollGeometry 类型和 onScrollGeometryChange 视图修饰符。这些工具为开发者提供了对滚动位置和交互的准确控制和洞察,增强了动态和相应敏捷的用户界面的开发。通过利用这些功能,你可以创建更具吸引力和直观的应用程序。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

泉缘泉

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表