Grid y GridRow en SwiftUI, crear grids complejos con muy pocas líneas de código con SwiftUI
Grid y GridRow en SwiftUI, crear grids complejos con muy pocas líneas de código con SwiftUI

Grids en SwiftUI #WWDC22

Grid es una nueva vista añadida a SwiftUI 4. Esta nueva vista va acompañada de GridRow para crear diferentes filas dentro del Grid. En el artículo de hoy exploramos esta nueva API y vemos todas las ventajas que nos va a aportar en nuestras apps. Lo comparamos con VStack y HStack de SwiftUI.

SwiftBeta

Tabla de contenido


👇 SÍGUEME PARA APRENDER SWIFTUI, SWIFT, XCODE, etc 👇
Grids en SwiftUI
Grids en SwiftUI

Hoy en SwiftBeta vamos a aprender a usar los Grids. Esta nueva vista de SwiftUI ha sido presentado en la WWDC22. Justo sacaron la Beta de Xcode y podemos probar estas nuevas APIs introducidas en iOS 16 y las mejoras de Xcode 14. Y es justo lo que vamos a ir viendo en los próximos posts. Vamos a ver algunas de las mejoras que han introducido para que nosotros los desarrolladores las podemos integrar en nuestra app.

Si quieres apoyar al canal, puedes suscribirte, de esta manera seguiré subiendo contenido semanal sobre Swift, SwiftUI, Xcode y mucho más.

Aquí podrás encontrar todos los cambios introducidos en SwiftUI

Apple Developer Documentation

Grids en SwiftUI 4.0

Lo que vamos a ver ahora es una nueva vista llamada Grid, esta vista ha sido introducidad en iOS 16 y tal y como indica nos permite crear Grids. Vamos a añadir la vista Grid y vamos a añadir dos GridRows:

struct ContentView: View {
    var body: some View {
        Grid {
            GridRow {
                Image(systemName: "figure.soccer")
                Text("Soccer")
            }
            GridRow {
                Image(systemName: "figure.basketball")
                Text("Basketball")
            }
        }
        .font(.largeTitle)
    }
}

Aquí te estarás preguntando, pero si esto lo podemos hacer exactamente igual con un VStack y HStack, y tienes casi toda la razón, lo único es que no es exactamente igual, y para verlo vamos a crear un VStack y dentro de HStacks

struct ContentView: View {
    var body: some View {
        VStack {
            Grid {
                GridRow {
                    Image(systemName: "figure.soccer")
                    Text("Soccer")
                }
                GridRow {
                    Image(systemName: "figure.basketball")
                    Text("Basketball")
                }
            }
            VStack {
                HStack {
                    Image(systemName: "figure.soccer")
                    Text("Soccer")
                }
                HStack {
                    Image(systemName: "figure.basketball")
                    Text("Basketball")
                }
            }
        }
        .font(.largeTitle)
    }
}

Para verlo más claro, hemos creado el VStack justo debajo del Grid, y si te fijas hay una sutil diferencia. Fíjate en el caso del Grid se ha aplicado automáticamente el mismo espacio entre las celdas de cada columna, podríamos decir que tiene en cuenta el ancho más grande de las celdas de la columna, y aplica ese tamaño a las celdas de la columna. Es por eso que vemos la vista del Grid tan uniforme. Para verlos más claro vamos a añadir un divider en el Grid y en el VStack:

struct ContentView: View {
    var body: some View {
        VStack {
            Grid {
                GridRow {
                    Image(systemName: "figure.soccer")
                    Text("Soccer")
                }
                Divider()
                GridRow {
                    Image(systemName: "figure.basketball")
                    Text("Basketball")
                }
            }
            VStack {
                HStack {
                    Image(systemName: "figure.soccer")
                    Text("Soccer")
                }
                Divider()
                HStack {
                    Image(systemName: "figure.basketball")
                    Text("Basketball")
                }
            }.padding(.top, 40)
        }
        .font(.largeTitle)
    }
}

Vemos claramente que en los Grid ha aplicado el mismo tamaño para cada celda. Si queremos que la vista Divider no ocupe todo el ancho de la pantalla y solo ocupe el tamaño del Grid, podemos usar el siguiente modificador:

struct ContentView: View {
    var body: some View {
        Grid {
            GridRow {
                Image(systemName: "figure.soccer")
                Text("Soccer")
            }
            Divider()
                .gridCellUnsizedAxes(.horizontal)
            GridRow {
                Image(systemName: "figure.basketball")
                Text("Basketball")
            }
        }
        .font(.largeTitle)
    }
}

Modificador gridCellColumns

Ahora vamos a utilizar un modificador de los Grid. se llama gridCellColumns y nos sirve para indicarle al GridRow el tamaño de ancho que queremos. Vamos a ver un ejemplo muy senicllo con rectangulos:

struct ContentView: View {
    var body: some View {
        Grid {
            GridRow {
                Rectangle()
                    .fill(.green.gradient)
                Rectangle()
                    .fill(.red.gradient)
            }
            GridRow {
                Rectangle()
                    .fill(.blue.gradient)
                Rectangle()
                    .fill(.purple.gradient)
            }
            GridRow {
                Rectangle()
                    .fill(.yellow.gradient)
            }
        }
        .font(.largeTitle)
    }
}

Imagina que quiero expandir el ancho del primer rectangulo, del verde. Podría utilizar este modificador para especificarle el ancho de columnas que quiero que ocupe:

import SwiftUI

struct ContentView: View {
    var body: some View {
        Grid {
            GridRow {
                Rectangle()
                    .fill(.green.gradient)
                    .gridCellColumns(2)
                Rectangle()
                    .fill(.red.gradient)
            }
            GridRow {
                Rectangle()
                    .fill(.blue.gradient)
                Rectangle()
                    .fill(.purple.gradient)
            }
            GridRow {
                Rectangle()
                    .fill(.yellow.gradient)
                    .gridCellColumns(4)
            }
        }
        .font(.largeTitle)
    }
}

¿Qué más podemos hacer con los Grids en SwiftUI?

Vamos a ver un ejempo más claro donde al añadir elementos dentro de un fila vemos como se adapta todo el Grid.

struct ContentView: View {
    var body: some View {
        Grid {
            GridRow {
                Text("Fila 1")
                ForEach(0..<2) { _ in Circle().fill(.red.gradient) }
            }
            GridRow {
                Text("Fila 2")
                ForEach(0..<6) { _ in Circle().fill(.orange.gradient) }
            }
            GridRow {
                Text("Fila 3")
                ForEach(0..<4) { _ in Circle().fill(.purple.gradient) }
            }
            GridRow {
                Text("Fila 4")
                ForEach(0..<5) { _ in Circle().fill(.green.gradient) }
            }
        }
        .frame(height: 200)
        .padding(.horizontal)
    }
}
Fíjate que he utilizado una nueva API llamada gradient, donde genera este efecto tan chulo de gradient

Si cambiamos el valor del ForEach del último GridRow, vemos como el ancho de cada celda de todas las filas de nuestro Grid también se actualiza. Esto lo podemos hacer porque cambiamos todas las vistas de golpe, pero imagina que tuviera un Grid con miles de filas o columnas, aquí por optimización sería mejor utilizar LazyVGrid y LazyHGrid (tal y como vimos en el curso de SwiftUI) ya que cargas las subvistas a medida que se necesitan (y no todas de golpe).
Ahora, vamos a añadir el mismo código original y vamos a modificar unos parámetros que acepta nuestro Grid.

Customizar el Grid en SwiftUI

Podemos customizar el spacio entre los elementos del Grid de la siguiente manera:

struct ContentView: View {
    var body: some View {
        Grid(horizontalSpacing: 10, verticalSpacing: 10) {
            GridRow {
                Text("Fila 1")
                ForEach(0..<2) { _ in Circle().fill(.red.gradient) }
            }
            GridRow {
                Text("Fila 2")
                ForEach(0..<6) { _ in Circle().fill(.orange.gradient) }
            }
            GridRow {
                Text("Fila 3")
                ForEach(0..<4) { _ in Circle().fill(.purple.gradient) }
            }
            GridRow {
                Text("Fila 4")
                ForEach(0..<5) { _ in Circle().fill(.green.gradient) }
            }
        }
        .frame(height: 200)
        .padding(.horizontal)
    }
}

Conclusión

Esta nueva vista en SwiftUI nos da mucha flexibilidad al crear componentes concretos para nuestra app. Con un aspecto muy uniforme y atractivo.