获取 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()
}
}
我找到了一个没有使用 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
使用新的 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()
}
}
我找到了一个没有使用 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