-1

I have two views that I want to use as possible parameters in another view. I've been using AnyView, but would much rather use @ViewBuilder instead; I'm not 100% sure on how to implement this though. See below:

View1

struct View1: View {
    let title: String
    let text: String

    var body: some View {
        HStack {
            Text(title)
            Text(text).bold()
        }
    }
}

View 2

struct View2: View {
    let title: String
    let text: String

    var body: some View {
        HStack {
            Text(title).bold()
            Text(text)
        }
    }
}

ParameterView - currently the view parameter being passed through is being wrapped in AnyView().

struct ParameterView: View {
    let title: String
    let view: any View

    var body: some View {
        HStack {
            Text(title)
            AnyView(view)
        }
    }
}

In practice:

struct ParameterView_Previews: PreviewProvider {
    static var previews: some View {
        VStack {
            ParameterView(
                title: "Noodles",
                view: View1(title: "£", text: "1.00")
            ) // Noodles £ 1.00

            ParameterView(
                title: "Mass",
                view: View2(title: "100", text: "g")
            ) // Mass 100 g
        }
    }
}
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
jarnold
  • 205
  • 1
  • 2
  • 12
  • Does this answer your question? https://stackoverflow.com/questions/56938805/how-to-pass-one-swiftui-view-as-a-variable-to-another-view-struct – jnpdx Feb 23 '23 at 15:40
  • The question is closed, not deleted. There is no need to reopen it; it is a complete question answer cycle. Do not add an edit / update and do not ask for reopening. – matt Feb 26 '23 at 11:18

1 Answers1

1

You're along the right lines - using @ViewBuilder is the way to go! We will combine this with the use of generics. I'll use your ParameterView as an example:

struct ParameterView<Content: View>: View {
    let title: String
    @ViewBuilder let view: Content

    var body: some View {
        HStack {
            Text(title)
            view
        }
    }
}

Here we're creating a view that uses a generic type Content that must conform to View. We use the @ViewBuilder property wrapper that basically says our property view is some function that will return a property of type Content and because Content: View we can use this property as we can with any View. Then all that's left to do is use that within the body.

Here's the usage:

struct UsageView: View {
    var body: some View {
        ParameterView(title: "Noodles") {
            View1(title: "£", text: "1.00")
        }
    }
}

Note that I'm using trailing closure syntax here because @ViewBuilder turns our property into a method.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Jack Smith
  • 26
  • 2
  • This worked - thank you! I appreciate the detailed explanation. This was a lot clearer than the question linked. – jarnold Feb 23 '23 at 16:17