How to use @ViewBuilder in SwiftUI

Jul 04, 2024#swiftui

In SwiftUI, @ViewBuilder is a special attribute used to build views. It is a result builder that allows you to construct views in a more declarative and readable manner. @ViewBuilder can be used to build complex view hierarchies by composing multiple views together within a single closure.

The @ViewBuilder attribute can be very useful when creating custom views that need to accept multiple child views, making the code more concise and readable. It is automatically used in many SwiftUI container views like VStack, HStack, ZStack, and ForEach.

Although the body property itself doesn’t require @ViewBuilder, the compiler automatically applies @ViewBuilder to it, allowing you to write multiple views inside the body without explicitly using a container view.

public protocol View {
    associatedtype Body : View
    @ViewBuilder var body: Self.Body { get }
}

You can use @ViewBuilder in different contexts, such as custom view initializers, methods, and computed properties, to enable the same declarative syntax used in SwiftUI’s built-in container views.

Using with initializers

Using @ViewBuilder with initializers allows the creation of views with complex hierarchies directly in the initializer, enabling the passing of multiple child views.

Here’s another example with a custom view initializer:

import SwiftUI

struct CustomContainer<Content: View>: View {
    let content: Content
    
    init(@ViewBuilder content: () -> Content) {
        self.content = content()
    }
    
    var body: some View {
        VStack {
            content
        }
    }
}

struct ContentView: View {
    var body: some View {
        CustomContainer {
            Text("This is inside the custom container")
            Text("Another view inside the custom container")
        }
    }
}

In this case, CustomContainer uses the @ViewBuilder attribute in its initializer to accept multiple views, allowing you to pass in multiple views when creating an instance of CustomContainer.

Using with methods

Using @ViewBuilder with methods encapsulates view-building logic within methods, making it easier to reuse and maintain. Methods can accept parameters, suitable for dynamic or parameterized view generation, allowing the same method to be used with different inputs to produce different views.

Here’s a basic example to illustrate the usage of @ViewBuilder in methods:

import SwiftUI

struct CustomView: View {
    var body: some View {
        VStack {
            content()
        }
    }
    
    @ViewBuilder
    private func content() -> some View {
        Text("Hello from CustomView")
        Text("This is another piece of text")
    }
}

In this example VStack is a container that arranges its children in a vertical stack. @ViewBuilder is applied to the content function, allowing it to return multiple Text views without wrapping them explicitly in a container like Group.

Using with computed properties

Using @ViewBuilder with computed properties can be a powerful way to modularize and reuse parts of your SwiftUI views. Suitable for defining view sections that do not require parameters and can be reused within the same view or other views.

struct ContentView: View {
    var body: some View {
        VStack {
            header
            bodyContent
            footer
        }
    }
    
    @ViewBuilder
    var header: some View {
        Text("Header")
            .font(.largeTitle)
            .padding()
        Divider()
    }
    
    @ViewBuilder
    var bodyContent: some View {
        Text("This is the main content area.")
            .padding()
        Text("You can add more views here.")
            .padding()
    }
    
    @ViewBuilder
    var footer: some View {
        Divider()
        Text("Footer")
            .font(.footnote)
            .padding()
    }
}