@ViewBuilder Usage

abdul ahad
5 min readMar 7, 2024

--

Photo by Christin Hume on Unsplash

in part 2 I discussed in detail how SwiftUI uses view builders to achieve a declarative DSL by flattening its child views into a single view. In this part, we’ll look at ways you can use ViewBuilderin your own code.

let’s recap

1- if a single View is returned from the ViewBuilder , it will do nothing and pass the single view back to whoever requested it. For example, the following View’s body will be of type `Text`.

2- if there’s more than one view that is being returned, the ViewBuilder will build a TupleView, that is it will flatten the interface into a single view. For example, the following View’s body will be of type TupleView<Text, Image>

However, when I try this I get an error so it’s important to understand the difference to understand SwiftUI better.

SwiftUI body has ViewBuilder Property wrapper attached to it in its protocol hence it can leverage the ability to flatten multiple children into a singular type which our subview Computed Property or buildViews function cannot. It will only work if both just return one view.

as you can see it can compile fine now

however, I want to break down my main view into subviews and have the ability to return multiple views from my computed property or function and not just a single view. how would I do that? There are 3 ways.

1- viewbuilder with properties

adding @ViewBuilderproperty wrapper now gives subView the ability to flatten multiple child views. It will leverage the power of SwiftUI Dsl but if you don’t have @ViewBuilderyou cannot leverage the DSl so this is one way for you to create reusable views in the form of a property.

2- viewbuilder with functions

similarly, if you apply @ViewBuilder property wrapper to a function it now gives buildViews the ability to flatten multiple child views into one single View. You can also take parameters to do any customizations you need.

3- Create a new SubView struct and reuse it in your main View Struct to achieve the same result.

All of the above are ways that we can use the power of ViewBuilders to separate your Views into smaller reusable views.

if it makes sense to share your views in different parts of the app we can go by creating a new struct

otherwise, if it’s breaking views within the view we can use properties or functions with ViewBuilders

Important to Understand

Since the GermanHallo Hello and spells views are parent views themselves with multiple children, they get unfolded when the stack iterates over its subviews like it did before and returns a single View which in this case Apple decides to return AnyView . The purpose of AnyView is to erase the type information of the view inside it. I’ll go into more detail about AnyView in another article.

As you can see we return a tupleView and inside tupleView we get multiple single views abstracted as AnyView.

Important Gotcha

This is a special property of view lists: when a container view like the HStack iterates over the view list, nested lists are recursively unfolded so that a tree of tuple views turns into a flat list of views

Applying a view modifier to a function or property with @viewbuilderwith multiple children like below we add .background(.red) to hello property view leads to applying the view modifier to all it’s childviews. This is because for to the HStack, this is exactly the same as writing all views directly in the stack’s view builder closure. so the hello View gets treated as 2 subviews when applying any view modifier.

we can also see that the stack’s spacing is equally applied between each of the views.

The same is also true if we use structs instead of functions.

However, there are exceptions you’ll find with Group.

Important Gotcha 2

A ViewBuilder function will only flatten the elements; it does not decide on the layout of these elements. This is the difference between returning two Views in a body (which will return a TupleView<ViewA, ViewB>) and an VStack with two views in it (which will return an VStack<TupleView<ViewA, ViewB>>.

looking at the example below since the body is marked as ViewBuilderby default SwiftUI will flatten all the child views in a TupleView to return a single view but since we haven’t provided any layout like a Vstack or Hstack it will assume a default layout provided by the system which seems to be vertical however there will be no VStack or Hstack in the type.

References

https://www.objc.io/books/thinking-in-swiftui/

GitHub: https://github.com/abdahad1996/SwiftUI_Bootcamp/blob/main/SwiftUI_Bootcamp/SwiftUI_Bootcamp/ViewBuilders/ViewBuilderUsage.swift

--

--

abdul ahad
abdul ahad

Written by abdul ahad

A software developer dreaming to reach the top and also passionate about sports and language learning

No responses yet