SwiftUI学习之GeometryReader和ScrollViewReader

一、 GeometryReader(几何读取器)

SwiftUI 中的 GeometryReader 是一个强大的布局工具,允许开发者根据父视图或屏幕的几何信息动态调整子视图的布局。

  • 作用:读取父视图的尺寸、安全区域、坐标空间等信息,并将这些数据通过 GeometryProxy 传递给子视图。
  • 注意: 频繁的读取可能几何信息导致性能问题,所以仅在必要时使用 GeometryReader,或结合 EquatableView 优化渲染。

例如下面这个例子,设置红色矩形占屏幕为2/3,蓝色占屏幕1/3

struct ContentView: View {
    var body: some View {
     HStack(spacing: 0){
            Rectangle().fill(.red)
                .frame(width: UIScreen.main.bounds.width * 0.66666)
            Rectangle().fill(Color.blue)
        }
    }
}

运行时没有问题,当你需要旋转设备是横屏时,就不满足需求。这时我们就可以使用GeometryReader动态获取

struct ContentView: View {
    var body: some View {
     GeometryReader { gemetry in
            HStack(spacing: 0){

                Rectangle().fill(.red)
                    .frame(width: gemetry.size.width * 0.6666)
                Rectangle().fill(Color.blue)
            }
        }
    }
监听滚动内容的几何变化
struct ContentView: View {
    @State private var scrollOffset: CGFloat = 0
    
    var body: some View {
        VStack {
            Text("导航栏(偏移:\(scrollOffset))")
                .background(scrollOffset < 0 ? Color.red : Color.blue)
            
            ScrollViewOffsetReader(offsetY: $scrollOffset)
        }
    }
}

struct ScrollViewOffsetReader: View {
    @Binding var offsetY: CGFloat
    
    var body: some View {
        ScrollView {
            GeometryReader { proxy in
                Color.clear
                    .preference(
                        key: ScrollOffsetPreferenceKey.self,
                        value: proxy.frame(in: .global).minY
                    )
            }
            .frame(height: 0)
            
            LazyVStack { /* 内容 */ }
        }
        .onPreferenceChange(ScrollOffsetPreferenceKey.self) { value in
            offsetY = value
        }
    }
}
  • GeometryReader 的作用:
    放置在 ScrollView 内容顶部,通过 proxy.frame(in: .global).minY 获取其在屏幕全局坐标系中的 Y 坐标。
    当用户滚动时,ScrollView 的内容会移动,导致 GeometryReader 的全局 Y 坐标变化。
  • PreferenceKey 的作用:
    将 GeometryReader 的 Y 坐标值传递给父视图。
  • onPreferenceChange:
    监听 PreferenceKey 的变化,实时更新 offsetY

二、ScrollViewReader(滚动视图读取器)

在 SwiftUI 中,ScrollViewReader 是一个强大的工具,可以让你通过编程控制滚动视图的定位。

一个通过 ScrollViewProxy 实例实现编程式滚动的视图。使用代理的 scrollTo(_:anchor:) 方法可执行精确滚动操作。

示例实现
以下示例创建了一个包含 100 个视图(组成颜色渐变)的 ScrollView,以及两个按钮(一个在顶部,一个在底部)。顶部按钮通过 ScrollViewProxy 滚动到底部按钮,反之亦然:

@Namespace var topID
@Namespace var bottomID

var body: some View {
    ScrollViewReader { proxy in
        ScrollView {
            // 顶部按钮(滚动到底部)
            Button("Scroll to Bottom") {
                withAnimation(.easeInOut) {
                    proxy.scrollTo(bottomID, anchor: .top)
                }
            }
            .id(topID)
            .padding()
            .background(Color.blue)
            .foregroundColor(.white)
            .cornerRadius(8)
            
            // 内容区域
            LazyVStack(spacing: 10) {
                ForEach(0..<100) { index in
                    Text("Item \(index)")
                        .frame(maxWidth: .infinity, minHeight: 50)
                        .background(index % 2 == 0 ? Color.gray.opacity(0.2) : Color.white)
                        .cornerRadius(8)
                        .id(index) // 为每个项目添加唯一标识
                }
            }
            .padding(.horizontal)
            
            // 底部按钮(滚动到顶部)
            Button("Top") {
                proxy.scrollTo(topID, anchor: .top)
            }
            .id(bottomID)
            .padding()
            .background(Color.green)
            .foregroundColor(.white)
            .cornerRadius(8)
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容