Using @ViewBuilder to create Views which support multiple children

Using the declaration of VStack we need to use @ViewBuilder for our content parameter. It is a closure but it shouldn't be @escaping it won't be good to store closure if we need only data from it. I assume that from the Apple declarations.

Also I believe that @inlinable is important because:

The @inlinable attribute exports the body of a function as part of a module's interface, making it available to the optimizer when referenced from other modules. More info here

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
            }
        } 
    }

To use it:

Layout {           
            Text("1")
            VStack {
                Text("1")
                Text("2")
            }
        }

UPD: As Matteo Pacini noted as a misleading info about @escaping.

We need to use @escaping for DynamicViewContent views. @escaping is used Apple's View structures for view structs that are accepting Collections(Array, Range, etc). Because the ForEach implements DynamicViewContent - a type of view that generates views from an underlying collection of data. List in its initializers also ForEach in Content

 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

Here's an example view that does nothing, just to demonstrate how to use @ViewBuilder.

struct Passthrough<Content>: View where Content: View {

    let content: () -> Content

    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
    }

    var body: some View {
        content()
    }

}

Usage:

Passthrough {
    Text("one")
    Text("two")
    Text("three")
}

Tags:

Swift

Swiftui