Solución:
Aquí hay una vista de ejemplo que no hace nada, solo para demostrar cómo usar @ViewBuilder
.
struct Passthrough<Content>: View where Content: View {
let content: () -> Content
init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
var body: some View {
content()
}
}
Uso:
Passthrough {
Text("one")
Text("two")
Text("three")
}
Usando la declaración de VStack
necesitamos usar @ViewBuilder
para nuestro parámetro de contenido. Es un cierre pero no debería be @escaping, no será bueno almacenar el cierre si solo necesitamos datos de él. Supongo que por las declaraciones de Apple.
Tambien creo que @inlinable
es importante porque:
El atributo @inlinable exporta el cuerpo de una función como parte de la interfaz de un módulo, haciéndolo disponible para el optimizador cuando se hace referencia a él desde otros módulos. Más info aquí
struct Layout <Content> : View where Content : View {
var content: Content
@inlinable public init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body : some View {
VStack {
Text("This is a layout")
self.content
}
}
}
Para usarlo:
Layout {
Text("1")
VStack {
Text("1")
Text("2")
}
}
UPD:
Como señaló Matteo Pacini como información engañosa sobre @escaping
.
Necesitamos usar @escaping
por DynamicViewContent
puntos de vista.
@escaping
se utilizan las estructuras de vista de Apple para estructuras de vista que aceptan colecciones (matriz, rango, etc.). Porque el ForEach
implementos DynamicViewContent
– un tipo de vista que genera vistas a partir de una colección de datos subyacente. List
en sus inicializadores también ForEach
en el contenido
public init<Data, RowContent>(_ data: Data, selection: Binding<Selection>?, action: @escaping (Data.Element.IdentifiedValue) -> Void, rowContent: @escaping (Data.Element.IdentifiedValue) -> RowContent) where Content == ForEach<Data, Button<HStack<RowContent>>>, Data : RandomAccessCollection, RowContent : View, Data.Element : Identifiable