获取 SwiftUI ScrollView 的当前滚动位置

Get the current scroll position of a SwiftUI ScrollView

使用新的 ScrolLViewReader,似乎可以通过编程方式设置滚动偏移量。

但我想知道是否也可以获取当前滚动位置?

好像ScrollViewProxy只自带了scrollTo方法,允许我们设置偏移量。

谢谢!

之前和之前都可以阅读。这是一个基于视图偏好的解决方案。

struct DemoScrollViewOffsetView: View {
    @State private var offset = CGFloat.zero
    var body: some View {
        ScrollView {
            VStack {
                ForEach(0..<100) { i in
                    Text("Item \(i)").padding()
                }
            }.background(GeometryReader {
                Color.clear.preference(key: ViewOffsetKey.self,
                    value: -[=10=].frame(in: .named("scroll")).origin.y)
            })
            .onPreferenceChange(ViewOffsetKey.self) { print("offset >> \([=10=])") }
        }.coordinateSpace(name: "scroll")
    }
}

struct ViewOffsetKey: PreferenceKey {
    typealias Value = CGFloat
    static var defaultValue = CGFloat.zero
    static func reduce(value: inout Value, nextValue: () -> Value) {
        value += nextValue()
    }
}

backup

我找到了一个没有使用 PreferenceKey 的版本。这个想法很简单 - 通过从 GeometryReader 返回 Color,我们可以直接在背景修饰符中设置 scrollOffset

struct DemoScrollViewOffsetView: View {
    @State private var offset = CGFloat.zero
    var body: some View {
        ScrollView {
            VStack {
                ForEach(0..<100) { i in
                    Text("Item \(i)").padding()
                }
            }.background(GeometryReader { proxy -> Color in
                DispatchQueue.main.async {
                    scrollOffset = -proxy.frame(in: .named("scroll")).origin.y
                }
                return Color.clear
            })
        }.coordinateSpace(name: "scroll")
    }
}

我有类似的需求,但使用 List 而不是 ScrollView,我想知道列表中的项目是否可见(List 预加载视图尚不可见,所以 onAppear()/onDisappear() 不合适)。

经过一些“美化”之后,我最终得到了这样的用法:

struct ContentView: View {
    var body: some View {
        GeometryReader { geometry in
            List(0..<100) { i in
                Text("Item \(i)")
                    .onItemFrameChanged(listGeometry: geometry) { (frame: CGRect?) in
                        print("rect of item \(i): \(String(describing: frame)))")
                    }
            }
            .trackListFrame()
        }
    }
}

由这个 Swift 包支持:https://github.com/Ceylo/ListItemTracking