Начиная с iOS 14 в SwiftUI добавили два новых представления LazyVGrid и LazyHGrid для отображения представлений в виде сетки с несколькими колонками/столбцами. Слово Lazy означает, что представление сетки не создает элементы, пока они не понадобятся. 
Первым шагом к использованию сетки есть создание списка элементов.
var colors: [Color] = [.orange, .green, .gray]
Затем создайте массив GridItem, описывающий как выглядит сетка. Вот пример фрагмента кода для описания сетки из двух столбцов
var grid = [GridItem(.flexible()), GridItem(.flexible())]
Наконец, разместите сетку, используя LazyVGrid и ScrollView.
ScrollView {
    LazyVGrid(columns: threeColumnGrid) {
        // Display the item
    }
}
Вы используете экземпляр GridItem для настройки расположения элементов в представлениях LazyHGrid и LazyVGrid. Элемент сетки представляет собой строку или столбец.
GridItems объявляются с использованием следующего синтаксиса
GridItem(sizing, spacing, alignment)
Есть три варианта указания размера элемента сетки.
flexible(minimum: CGFloat, maximum: CGFloat) указывает один гибкий элемент в доступном пространстве с необязательными параметрами для минимального и максимального размера.adaptive(minimum: CGFloat, maximum: CGFloat) указывает, что размер строки или столбца регулируется таким образом, чтобы максимально возможное количество элементов помещалось в доступное пространство.fixed(CGFloat) определяет один элемент фиксированного размера в доступном пространстве.Flexible
Flexible макет сетки позволяет указать диапазон размеров, определяя при этом количество столбцов. Мы можем предоставить минимум и максимум, но и без этого он прекрасно работает. Размер элемента рассчитывается путем деления доступного пространства на количество элементов.
struct ContentView: View {    
    private var colors: [Color] = [.orange, .green, .gray]
    private var items = [GridItem(.flexible(minimum: 60)), GridItem(.flexible()), GridItem(.flexible())]
    struct ItemView: View {
        var index: Int        
        var color: Color
        var body: some View {
            Text("\(index)")
                .frame(minWidth: 50, maxWidth: .infinity, minHeight: 100)
                .background(color)
                .cornerRadius(4)
        }
    }
    var body: some View {
        ScrollView {
            LazyVGrid(columns: items, spacing: 4) {
                ForEach((0...10), id: \.self) { index in
                    ItemView(index: index, color: colors[index % colors.count])
                }
            }
            .padding(4)
        }
    }
}
Adaptive
Adaptive макет сетки является, наверное, наиболее используемым. Он заполняет пространство таким количеством столбцов или строк, которое помещается в сетку. Чтобы использовать адаптивный размер, измените массив items, чтобы он содержал один адаптивный элемент, как показано ниже
private var items = [GridItem(.adaptive(minimum: 80))]
Это изменение приведет к тому, что в сетке будет отображаться как можно больше столбцов с ограничением, согласно которому ширина столбца не может быть меньше 80 dp.
Fixed
Fixed макета сетки позволяет задавать строки или столбцы определенного размера. При использовании только фиксированных GridItems в списке, количество элементов будет определять количество строк или столбцов. Например, следующий список при передаче в представление LazyVGrid отобразит сетку, содержащую один столбец шириной 80 dp.
private var items = [GridItem(.fixed(80))]
С другой стороны, следующий список будет отображать сетку из трех столбцов со столбцами размером 30dp, 40dp и 50dp соответственно.
private var items = [GridItem(.fixed(30)), GridItem(.fixed(40)), GridItem(.fixed(50))]
При работе с сетками также можно комбинировать конфигурации размеров GridItem. Например, следующий список будет отображать первый столбец каждой строки с фиксированной шириной, а второй и третий столбцы будут иметь одинаковый размер, чтобы занимать оставшееся место
private var items = [GridItem(.fixed(30)), GridItem(), GridItem()]
LazyHGrid
Горизонтальные сетки работают почти так же, как вертикальные, за исключением того, что конфигурация основана на строках, а не на столбцах, и значения minimum и maximum относятся к высоте строки, а не к ширине столбца.
struct ContentView: View {
    private var colors: [Color] = [.orange, .green, .gray]
    private var items = [GridItem(.adaptive(minimum: 40))]
    struct ItemView: View {
        var index: Int
        var color: Color
        var body: some View {
            Text("\(index)")
                .frame(minWidth: 50, minHeight: 50, maxHeight: .infinity)
                .background(color)
                .cornerRadius(4)
        }
    }
    var body: some View {
        ScrollView(.horizontal) {
            LazyHGrid(rows: items, spacing: 4) {
                ForEach((0...50), id: \.self) { index in
                    ItemView(index: index, color: colors[index % colors.count])
                }
            }
            .padding(4)
        }
    }
}