I want a SwiftUI LazyGrid that can change its GridItem size with an animation, but a crash occurs while scrolling up after the size is made smaller.
Steps to Reproduce:
1 - scroll to bottom of 'xLarge' size grid
2 - change to 'large' size using Picker
3 - scroll up after size change animation has finished
Crash Error: Thread 1: EXC_BREAKPOINT (code=1, subcode=0x18d9f3b64)
Code Snippets:
import SwiftUI
@main
struct GridScrollDefectApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
import SwiftUI
struct ContentView: View {
@State var cellSize: CellSize = .xLarge
var body: some View {
let sizes = cellSize.adaptiveSizes
let objects = Array(0..<30).map { _ in return TestObject() }
VStack {
Picker("Size", selection: $cellSize.animation()) {
ForEach(CellSize.allCases) { cellSize in
Text(cellSize.rawValue.localizedCapitalized)
.tag(cellSize)
}
}
ScrollView {
LazyVGrid(columns: [GridItem(.adaptive(minimum: sizes.min, maximum: sizes.max))]) {
ForEach(objects) { _ in
Image(systemName: "multiply")
.resizable()
.aspectRatio(contentMode: .fit)
}
}
}
}
}
}
import Foundation
class TestObject: Identifiable {
var id: UUID = UUID()
}
enum CellSize: String, CaseIterable, Identifiable {
case xLarge, large
var id: RawValue { return rawValue }
var adaptiveSizes: (min: CGFloat, max: CGFloat) {
switch self {
case .xLarge:
return (330,400)
case .large:
return (150,200)
}
}
}
I've tried various combinations of storing the cellSize and the objects array in @State, @Binding, and a @ObservedObject @Published var, and all exhibit this issue. The only half-work-around I've found is to refresh the views using a .id() modifier on the grid, which avoids the crash, but also removes the resizing animation.