I am trying to ascertain which GridItem would effectively be at position x:0, y:0.
To achieve this I am simply trying to use a preferenceKey and GeometryReader.
I am adding an .overlay to my GridItems and on the GridItem at gridItemIndex 0 adding the GeometryReader around a Color.clear. My expected logic is to track the Y position of that GridItem. Then by dividing that Y offset by the height of each GridItem I will get which item is currently at the top.
I have this working to a point. Once the GridItem at index “gridItemIndex” position 0 is above a certain offset it is no longer read and the y position rests to 0.0. My assumption for this is due to the view being reused?
Currently I am not getting the reading above 40 but I need to get until the bottom of the LazyVGrid appears.
Here is my code
struct DetectScrollPosition: View {
let gridRowLayout = Array(repeating: GridItem(spacing: 0), count: 7)
@State private var scrollPosition: Int = 0
var body: some View {
NavigationView {
ScrollView (.vertical){
LazyVGrid(columns: gridRowLayout, spacing: 0){
ForEach(0..<1092, id: \.self) { gridItemIndex in
Text("\(abs(gridItemIndex / 7))")
.overlay {
if gridItemIndex == 0 {
GeometryReader { geometryProxy in
Color.clear
.updateViewsYPosition(geometryProxy)
}
}
}
}
}
.onPreferenceChange(ScrollOffsetPreferenceKey.self) { value in
self.scrollPosition = abs(Int(value))
}
}
.coordinateSpace(.named("scroll"))
.navigationTitle("The Top Row is: \(scrollPosition)")
.navigationBarTitleDisplayMode(.inline)
}
}
}
struct ScrollOffsetPreferenceKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
}
}
extension View {
func updateViewsYPosition(_ geometryProxy: GeometryProxy) -> some View {
let offset = geometryProxy.frame(in: .named("scroll")).origin.y / geometryProxy.frame(in: .named("scroll")).height
return self.preference(key: ScrollOffsetPreferenceKey.self, value: offset)
}
}





