View composition with @ViewBuilder
@ViewBuilder property wrapper allows to pass views as parameter to build custom views. It’s posible to create our own views like HStack or VStack.
In this example a custom sheet view receives a closure as parameter that provides the views that will be injected.
struct CustomSheetView<Content: View>: View {
let content: Content
init(i@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
ZStack {
Rectangle()
.foregroundColor(Color(.displayP3, white: 0, opacity: 0.2))
VStack(alignment: .leading) {
Spacer()
VStack(alignment: .leading) {
content // Here the completion injects the views
}
.padding(20)
.frame(maxWidth: .infinity, minHeight: 500)
.background(Color(.displayP3, white: 0.95, opacity: 1))
.cornerRadius(25, corners: [.topLeft, .topRight])
}
}
}
}
Then this custom view can take views as the rest of the swiftui components.
struct ExampleView: View {
var body: some View {
CustomSheetView {
Text("My Title")
Text("My Description")
}
}
}
Sometimes we just want to simplify the logic of our views. In this case we can create a method that returns some View.
private extension HeaderView {
@ViewBuilder func makeEditButton() -> some View {
if isEditing {
CloseButton()
} else {
EditButton()
}
}
}
And then use the method to inject the view removing the logic and increasing the readibility.
struct HeaderView: View {
var body: some View {
HStack {
Title("My title")
makeEditButton()
...
}
}
}