保存 ScrollViews 位置并稍后滚动回它(偏移到位置) [英] Save ScrollViews position and scroll back to it later (offset to position)
问题描述
我找到了一种使用 GeometryReader
和 PreferenceKey
保存 ScrollViews offset 的方法.
struct TestScrollBackView:查看{@State 私有变量存储:Int = 0@State private var current: [Int] = []var主体:一些视图{ScrollViewReader { 代理在虚拟堆栈{堆栈{按钮(商店"){//硬代码仅用于演示!!!storage = current.sorted()[1]//第一个被 LazyVStack 移出屏幕打印(!!存储\(存储)")}按钮(恢复"){proxy.scrollTo(存储,锚点:.top)打印([x] 恢复 \(存储)")}}分隔线()滚动视图{懒惰VStack {ForEach(0..<1000, id: \.self) { obj in文本(项目:\(对象)").onAppear {打印(">>添加\(obj)")current.append(obj)}.onDisappear {current.removeAll { $0 == obj }打印(<<删除\(obj)")}.id(对象)}}}}}}}
I have found a way to save a ScrollViews offset with a GeometryReader
and a PreferenceKey
.
SwiftUI | Get current scroll position from ScrollView
And the ScrollViewReader
has a method scrollTo
to scroll to a set position.
The problem is, that the first one saves an offset while the second method expects a position (or an id, which is similar to the position in my case). How can I convert the offset to a position/id or is there any other way to save and load a ScrollViews position?
Here is the code I have now but it does not scroll the way I want:
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")
And in the onAppear
of the View I want to set scrollTarget
to the saved position. But it scrolls anywhere but not to the position I want.
I thought about dividing the offset by the size of one item but is that really the way to go? It does not sound very good.
You don't need actually offset in this scenario, just store id of currently visible view (you can use any appropriate algorithm for your data of how to detect it) and then scroll to view with that id.
Here is a simplified demo of possible approach. Tested with 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)
}
}
}
}
}
}
}
这篇关于保存 ScrollViews 位置并稍后滚动回它(偏移到位置)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!