RXP
RXP

Reputation: 687

how to set a View as a parameter in SwiftUI

I am trying to provide an option through a Configuration struct to show a custom view. I am not sure how to accomplish this. I tried a number of options but I keep getting compile errors. May be my approach to do this is wrong! I appreciate your help!

Here is what I tried:

configuration struct that provides options to set color, width and custom content, etc...

struct Configuration {
    var color: Color
    ....
    var customView: (([String])->AnyView?) = nil // <- this compiles but not sure if this is the right way to do it!
    ...
}

defining my custom view:

struct CustomView: View {
    var values: [String]
    var body: some View {
        VStack {
            ForEach(values.indices, id:\.self) { index in
                Text(values[index])
            }
        }
    }
}

Here is how I am using it and where I get the compiler error:

struct ContentView: View {
    var config = Configuration()

    config.customView = CustomView(["A", "B"]) // <-- Error: Cannot assign value of type CustomView to type ([String]) -> AnyView

    var body: some View {
        VStack {
            .... // display other content
        }
        .overlay(showCustomView())
    }

    @ViewBuilder
    private func showCustomView() -> some View {
        if let customContent = config.customView {
            customContent()
        } else {
            EmptyView()
        }

    }
}

Upvotes: 2

Views: 1230

Answers (1)

Asperi
Asperi

Reputation: 258365

Here is possible solution (as far as I understood your intention) - you need generics in configuration to be able to use it with any view.

Here is a demo. Prepared with Xcode 12.4.

struct Configuration<V: View> {   // << view dependent
    var color: Color
    var customView: (([String]) -> V?)? = nil    // << view builder
}

struct CustomView: View {   // no changes
    var values: [String]
    var body: some View {
        VStack {
            ForEach(values.indices, id:\.self) { index in
                Text(values[index])
            }
        }
    }
}

struct ContentView: View {

    var config = Configuration(color: .black) {   // << create config !!
        CustomView(values: $0)                    // ... and specify view !!
    }

    var body: some View {
        VStack {
            Text("")
        }
        .overlay(showCustomView())
    }

    @ViewBuilder
    private func showCustomView() -> some View {
        if let customContent = config.customView {
            customContent(["A", "B"])              // << inject params !!
        } else {
            EmptyView()
        }
    }
}

Upvotes: 1

Related Questions