保存 ScrollViews 位置并稍后滚动回该位置(偏移位置)

L3n*_*n95 4 ios swiftui geometryreader swiftui-scrollview

我找到了一种用 a和 a保存 ScrollViews偏移量的方法。GeometryReaderPreferenceKey

SwiftUI | 从 ScrollView 获取当前滚动位置

并且有一个滚动到设定位置ScrollViewReader的方法。scrollTo

滚动到

问题是,第一个方法保存偏移量,而第二个方法需要一个位置(或一个 id,与我的情况下的位置类似)。如何将偏移量转换为位置/id 或者是否有其他方法来保存和加载 ScrollViews 位置?

这是我现在拥有的代码,但它没有按照我想要的方式滚动:

ScrollView {
    ScrollViewReader { scrollView in
        LazyVGrid(columns: columns, spacing: 0) {
            ForEach(childObjects, id: \.id) { obj in
                CustomView(obj: obj).id(obj.id)
            }
        }
        .onChange(of: scrollTarget) { target in
            if let target = target {
                scrollTarget = nil
                scrollView.scrollTo(target, anchor: .center)
            }
        }
        .background(GeometryReader {
            Color.clear.preference(key: ViewOffsetKey.self,
                value: -$0.frame(in: .named("scroll")).origin.y)
        })
        .onPreferenceChange(ViewOffsetKey.self) { // save $0 }
    }
}.coordinateSpace(name: "scroll")
Run Code Online (Sandbox Code Playgroud)

onAppear视图中我想设置scrollTarget为保存的位置。但它滚动到任何地方,但没有滚动到我想要的位置。

我考虑过将偏移量除以一个项目的大小,但这真的是正确的方法吗?听起来不太好。

Asp*_*eri 10

在这种情况下,您不需要实际偏移,只需存储当前可见视图的 id(您可以对如何检测它的数据使用任何适当的算法),然后滚动到具有该 id 的视图。

这是可能方法的简化演示。使用 Xcode 12.1/iOS 14.1 进行测试

演示

struct TestScrollBackView: View {
    @State private var stored: Int = 0
    @State private var current: [Int] = []
    
    var body: some View {
        ScrollViewReader { proxy in
            VStack {
                HStack {
                    Button("Store") {
                        // hard code is just for demo !!!
                        stored = current.sorted()[1] // 1st is out of screen by LazyVStack
                        print("!! stored \(stored)")
                    }
                    Button("Restore") {
                        proxy.scrollTo(stored, anchor: .top)
                        print("[x] restored \(stored)")
                    }
                }
                Divider()
                ScrollView {
                    LazyVStack {
                        ForEach(0..<1000, id: \.self) { obj in
                            Text("Item: \(obj)")
                                .onAppear {
                                    print(">> added \(obj)")
                                    current.append(obj)
                                }
                                .onDisappear {
                                    current.removeAll { $0 == obj }
                                    print("<< removed \(obj)")
                                }.id(obj)
                        }
                    }
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)