2

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.

teaseaque
  • 280
  • 2
  • 6

0 Answers0