Bob*_*Bob 3 scrollview swiftui scrollviewreader
我正在寻找一种简洁的方法来识别 ScrollView 中当前可见的顶行。我希望 NavigationTitle 显示当前行号。有没有办法用 ScrollViewReader 来做到这一点,或者我必须用 GeometryReader 做些什么?在下面的代码中,我希望 myRowNumber 在用户上下滚动时更新。提前致谢。
struct ContentView: View {
let myArray: [Int] = [Int](1...100)
@State private var myRowNumber: Int = 50
var body: some View {
NavigationView {
ScrollView {
LazyVStack{
ScrollViewReader { proxy in
ForEach(myArray, id: \.self) { index in
Text("Row \(index)").id(index).font(.title)
}
.onAppear {
proxy.scrollTo(50, anchor: .top)
}
}
}
}
.navigationTitle("Current row = \(myRowNumber)")
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果您的部署目标是 iOS 17(或 macOS 14 等)或更高版本,您可以使用修饰符scrollPosition(id:)
来跟踪滚动视图的顶部可见行。
所以你想要这样的东西:
SwiftUI 不提供直接读取顶行的方法,因此我们必须使用其他工具来计算它。
我们需要知道每一行相对于滚动视图顶部的位置。这意味着两件事:获取Anchor
每一行的 ,并计算该行Anchor
相对于 顶部的y 坐标ScrollView
。
我们可以Anchor
使用anchorPreference
修饰符收集 s,但首先我们需要创建一个PreferenceKey
类型来管理集合。
struct AnchorsKey: PreferenceKey {
// Each key is a row index. The corresponding value is the
// .center anchor of that row.
typealias Value = [Int: Anchor<CGPoint>]
static var defaultValue: Value { [:] }
static func reduce(value: inout Value, nextValue: () -> Value) {
value.merge(nextValue()) { $1 }
}
}
Run Code Online (Sandbox Code Playgroud)
要将 an 变成Anchor<CGPoint>
实际的CGPoint
,我们需要 a GeometryProxy
。假设我们有一个代理,我们希望从 y 坐标至少为零的行中选择 y 坐标最小的行。
private func topRow(of anchors: AnchorsKey.Value, in proxy: GeometryProxy) -> Int? {
var yBest = CGFloat.infinity
var answer: Int? = nil
for (row, anchor) in anchors {
let y = proxy[anchor].y
guard y >= 0, y < yBest else { continue }
answer = row
yBest = y
}
return answer
}
Run Code Online (Sandbox Code Playgroud)
现在我们需要将 aGeometryReader
包裹起来ScrollView
以获取 a GeometryProxy
,并.overlayPreferenceValue
在 the 中使用修饰符GeometryReader
来访问收集的Anchor
s。
struct ContentView: View {
let myArray: [Int] = [Int](1...100)
@State private var myRowNumber: Int = 50
var body: some View {
NavigationView {
GeometryReader { proxy in
ScrollView {
LazyVStack{
ScrollViewReader { proxy in
ForEach(myArray, id: \.self) { index in
Text("Row \(index)").id(index).font(.title)
.anchorPreference(
key: AnchorsKey.self,
value: .center
) { [index: $0] }
}
.onAppear {
proxy.scrollTo(50, anchor: .top)
}
}
}
}
.overlayPreferenceValue(AnchorsKey.self) { anchors in
let i = topRow(of: anchors, in: proxy) ?? -1
Color.clear
.navigationTitle("Current row = \(i)")
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1752 次 |
最近记录: |