swiftswiftuiclosures

What is the correct syntax for implementing a closure that allows the user to insert additional views?


I'd like to implement a closure additionalContent that allows a calling class to add extra UI to a view:

struct RandomView: View
{
    private var additionalContent: (() -> some View)?
    
    var body: some View
    {
        Text("1")
        
        if let additionalContent = self.additionalContent
        {
            additionalContent
        }
        
        Text("2")
    }
}

However, I am getting the error "Type '() -> some View' cannot conform to 'View' " after the optional is unwrapped.

I've tried using "any View" and "View" as the parameters and it's the same thing. Tried adding @ViewBuilder to the property declaration but it complains that a getter needs to be added? What is the correct syntax to accomplish this?


Solution

  • additionalContent is a closure that returns a some View, so you just need to invoke that closure.

    if let additionalContent
    {
        additionalContent()
    }
    

    That said, taking the closure in the initialiser and immediately invoke it in the initialiser immediately is more commonly seen in built-in SwiftUI views (though obviously this only works if the view builder closure takes no parameters). Also, use EmptyView instead of an optional to represent the absence of additional content.

    struct RandomView<Content: View>: View
    {
        private let additionalContent: Content
        
        init(@ViewBuilder additionalContent: () -> Content) {
            self.additionalContent = additionalContent()
        }
        
        init() where Content == EmptyView {
            self.additionalContent = EmptyView()
        }
        
        var body: some View
        {
            Text("1")
            additionalContent
            Text("2")
        }
    }