Hi,
I tried to achieve the same thing, i.e. multiple optional viewbuilder parameter, and came to a solution that works well.
Let's take a swipeable view where you have 3 types of content :
struct SwipeItem<Content: View, Left: View, Right: View>: View{
private var content: () -> Content
private var left: (() -> Left)?
private var right: (() -> Right)?
private init(@ViewBuilder content: @escaping () -> Content, left: (() -> Left)?, right: (() -> Right)?){
self.content = content
self.left = left
self.right = right
}
var body: some View{
// simplified body
HStack{
left?()
content()
right?()
}
}
}
You have on constructor that accept both optional parameters and you can make it private.
Then you can use extensions as :
extension SwipeItem{
init(@ViewBuilder content: @escaping () -> Content, @ViewBuilder left: @escaping () -> Left, @ViewBuilder right: @escaping () -> Right){
self.content = content
self.left = left
self.right = right
}
init(@ViewBuilder content: @escaping () -> Content, @ViewBuilder left: @escaping () -> Left) where Right == EmptyView{
self.init(content: content, left: left, right: nil)
}
init(@ViewBuilder content: @escaping () -> Content, @ViewBuilder right: @escaping () -> Right) where Left == EmptyView{
self.init(content: content, left: nil, right: right)
}
}
EmptyView represents the "absence" of view. So you can attach a "where" clause next to your constructor.
Then you can use it as :
struct SwipeItem_Previews: PreviewProvider{
static var previews: some View{
SwipeItem {
Text("test")
} left:{
Text("left")
} right: {
Text("right")
}
SwipeItem {
Text("test")
} left:{
Text("left")
}
}
}
I've been looking for a solution and found nothing to explain this (had to read a lot of docs about generics).
Hope this can help.