ah. thanks for the video, I wasn't scrolling far enough but I couldn't tell where I was.
I modified your code so it is easier to see what cell you're at. I couldn't reproduce it with an array of only 30, or even 100 Ints. But with 150 (as below), I can press on C14 and the scroll position will jump so that I'm looking at E14. Your code doesn't modify the scroll position, so this looks like a bug to me.
struct ContentView: View {
let strings: [String] = ["A", "B", "C", "D", "E"]
let ints: [Int] = Array(1...150)
@State var selectedCell: String?
var body: some View {
ZStack {
ScrollView {
VStack {
ForEach(strings, id: \.self) { string in
VStack {
HStack {
Text(string)
Spacer()
}
LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())]) {
ForEach(ints, id: \.self) { int in
VStack {
Text(string + String(int))
Spacer()
}
.frame(minWidth: 0, maxWidth: .infinity)
.frame(height: 200)
.background(
RoundedRectangle(cornerRadius: 5)
.fill(int % 2 == 0 ? .orange : .green)
)
.onTapGesture {
self.selectedCell = string + String(int)
}
}
}
}
}
}
.padding()
}
if let selectedCell {
VStack {
Spacer()
Text(selectedCell)
Spacer()
Button {
self.selectedCell = nil
} label: {
Image(systemName: "x.circle")
.resizable()
.scaledToFit()
.frame(width: 30)
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}
}
}
}
the good news is that it seems you can work around it by making the second VStack persist, regardless of whether you are displaying a selection or not. Modify the second VStack like this (remove the if let selectedCell condition)
VStack {
Spacer()
Text(selectedCell ?? "you don't see me")
.foregroundColor(selectedCell == nil ? .clear : .black)
Spacer()
Button {
self.selectedCell = nil
} label: {
Image(systemName: "x.circle")
.resizable()
.scaledToFit()
.frame(width: 30)
}
}