swiftuilazyvgrid

Is that possible to scroll a LazyVGrid to show a particular item in the middle?


I have this LazyVGrid showing a grid with 4 columns and countless icons.

private var columns: [GridItem] = [
  GridItem(.adaptive(minimum: .infinity, maximum: .infinity), spacing: 0),
  GridItem(.adaptive(minimum: .infinity, maximum: .infinity), spacing: 0),
  GridItem(.adaptive(minimum: .infinity, maximum: .infinity), spacing: 0),
  GridItem(.adaptive(minimum: .infinity, maximum: .infinity), spacing: 0)
]

var body: some View {
  ScrollView{ //{ proxy in
    ZStack{
        Color.blue
        
        LazyVGrid(
          columns: columns,
          alignment: .center,
          spacing: 10,
          pinnedViews: []
        ) {
          ForEach(items, id:\.self.title) { item in
            Text(item.title)
              .listRowBackground(Color.clear)
              .id(item.title)
              .padding(.horizontal, 15)
          }
        }
        .listStyle(PlainListStyle())
      }
    }
}

Now I want to scroll down the grid, programmatically, to show a particular item.

Is that possible to do that on a Grid?

Lists can do that easily but what about LazyVGrids?


Solution

  • The simplest way is to wrap inside ScrollViewReader and change ForEach to iterate through array by index. I made an array mocked with numbers in range 0...200, and created a button to scroll to element at index 120.

    var body: some View {
        ScrollViewReader { proxy in
            ScrollView {
                VStack {
                    Button {
                        withAnimation {
                            proxy.scrollTo(120, anchor: .center)
                        }
                    } label: {
                        Text("Scroll")
                    }
                    
                    ZStack {
                        Color.blue
                        
                        LazyVGrid(
                            columns: columns,
                            alignment: .center,
                            spacing: 10,
                            pinnedViews: []
                        ) {
                            //Iterating by index in this example, should use id instead
                            ForEach(0..<items.count, id: \.self) { i in
                                Text(items[i].title)
                                    .listRowBackground(Color.clear)
                                    .id(i) //<- put index here
                                    .padding(.horizontal, 15)
                            }
                        }
                        .listStyle(PlainListStyle())
                    }
                }
            }
        }
    }
    

    Output:

    enter image description here