En ocasiones no queremos construir un componente hoja, sino un contenedor que almacene a otros subcomponentes.
En el siguiente ejemplo, Container es una vista genérica que espera recibir content de tipo @ViewBuilder que retorna Content, que conforma View. Observar:
- Se debe definir la distribución a pintar dentro de
Container, en este caso: conHStack. - Se define un conjunto de subvistas dentro de un "closure" en
ContentView.
struct Container<Content: View>: View {
@ViewBuilder var content: Content
var body: some View {
HStack {
content
}
}
}
struct ContentView: View {
var body: some View {
Container {
Text("Uno")
Text("Dos")
}
}
}
Manipulando los items individualmente desde el contenedor
Para acceder a los items en Container se usa ForEach.init(subviews:content:) o Group.init(subviews:transform:).
La primera aproximación (ForEach) permite recorrer todos los elementos, uno a uno, mientras que la segunda (Group) da acceso a todos los ítems -Lo cual es útil si se quiere hacer una operación sobre la colección antes de operarla con ForEach.
struct Container<Content: View>: View {
@ViewBuilder var content: Content
var body: some View {
HStack {
ForEach(subviews: content) { subview in
subview
.padding()
.background(.red.opacity(0.5))
}
}
}
}
Inyectando un valor de configuración desde una subvista hacia el contenedor
Algunas veces el contenedor no tiene información suficiente para configurar a la subvista. Por esta razón, la subvista debe hacer una "inyección reversa". Para ello:
- Se agrega una nueva llave
xenContainerValuesen una extensión por medio de una propiedad, con un valor por defecto, marcada como@Entry. - Se inyecta el valor en la subvista con
containerValue(_:_:)usando la llavexdefinida en el paso anterior. - Luego, se accede a la llave
xen el atributocontainerValuesde tipoContainerValuesde la subvista en cuestión. - Con base en
x, se hace la modificación sobre la subvista que haga falta.
Por ejemplo:
extension ContainerValues {
// ⚠️ 1. Se crea la nueva llave con valor por defecto
@Entry var valida = false
}
struct Container<Content: View>: View {
@ViewBuilder var content: Content
var body: some View {
HStack {
ForEach(subviews: content) { subview in
// ⚠️ 3. Se extrae el valor del containerValues
let valida = subview.containerValues.valida
subview
.padding()
.background(valida ? .green.opacity(0.5) : .red.opacity(0.5)) // ⚠️ 4. Se hace la modificación necesaria
}
}
}
}
struct ContentView: View {
var body: some View {
Container {
// ⚠️ 2. Se inyecta el valor en la subvista
Text("Uno")
.containerValue(\.valida, true)
// ⚠️ 2. Aquí se toma el valor por defecto
Text("Dos")
// ⚠️ 2. Aquí se vuelve a inyectar
Text("Tres")
.containerValue(\.valida, false)
}
}
}


Top comments (0)