swiftuilazyvgrid

Is there a way to make items on a LazyVGrid snap when they are full in view?


I have a LazyVGrid like this.

struct ContentView: View {
  
  private var columns: [GridItem] = [
    GridItem(.adaptive(minimum: .infinity, maximum: .infinity), spacing: 0)
  ]
  
  private var items = Array(stride(from: 0, to: 100, by: 1))
  
    var body: some View {
      ScrollViewReader { proxy in
        ScrollView {
          VStack {
              LazyVGrid(
                columns: columns,
                alignment: .center,
                spacing: 10,
                pinnedViews: []
              ) {
                ForEach(0..<items.count, id: \.self) { i in
                  Text("\(i)")
                    .frame(width:UIScreen.main.bounds.width - 20, height:UIScreen.main.bounds.height - 150)
                    .background(Color.red)
                    .foregroundColor(.white)
                    .id(i)
                }
              }
          }
        }
      }
      .padding()
    }
}

In this case, the grid shows just one cell per page (please run on iPhone 15 pro to see what I mean).

Is there a way to make a cell snap to the vertical center when the user releases the finger during scroll and the cell's top Y passed the center point (supposing the cell is being scrolled up) or the bottom Y passed the vertical center (supposing the cell is being scrolled down), like it was a page control?


Solution

  • iOS 17 Example

    There are some nice to have goodies that they gave us with ScrollView in the latest iOS. Some of those being: scrollTargetLayout and scrollTargetBehavior:

    var body: some View {
            ScrollViewReader { proxy in
                ScrollView {
                    VStack {
                        // LazyGrid - removed this to reduce confusion
                    }
                    .scrollTargetLayout() // <-- Here
                }
                .scrollTargetBehavior(.viewAligned(limitBehavior: .always)) // <-- Here
            }
            .padding()
        }
    

    In the example above, viewAligned is limiting the behavior, which just means its scrolling one at a time.