Passing One SwiftUI View as a Parameter to Another SwiftUI View

Chase
3 min readApr 10, 2024

--

We will go over the easiest way to pass one view to another and a slightly more advanced method that will allow your view API to look and feel more like an official SwiftUI view API.

The text of Passing Views above cascading views of the swift logo

Before we get started, please take a couple of seconds to follow me and 👏 clap for the article so that we can help more people learn about this useful content.

What we will build

We will build two custom components the take a simple text value as the first parameter, and the second two parameter will be custom views. The two components will display what is passed to them in the same way, but the implementation and APIs will each be different to cover most use cases.

The Easy Way

I am calling this the easy way because it is easier to see the changes that are made to your code using the previews, and because it is possibly the most frequently suggested way by various people across the internet. I want to show both methods here so that we can all see the differences in implementation in a more or less side by side comparison.

//  MyCustomView.swift
import SwiftUI

struct MyCustomView<ChildOneContent: View, ChildTwoContent: View>: View {
let text: LocalizedStringKey
@ViewBuilder let childViewOne: ChildOneContent
@ViewBuilder let childViewTwo: ChildTwoContent

init(
_ text: LocalizedStringKey,
childViewOne: ChildOneContent,
childViewTwo: ChildTwoContent
) {
self.text = text
self.childViewOne = childViewOne
self.childViewTwo = childViewTwo
}

var body: some View {
VStack {
Text(text)
childViewOne
childViewTwo
}
}
}

#Preview {
MyCustomView(
"Test",
childViewOne: HStack {
Text("test")
Text("one")
},
childViewTwo: VStack {
Text("test")
Text("two")
}
)
}

The call site for this implementation can be seen in the code below. As you can probably tell, we have parenthesis around the entire function (even our custom views that we are passing) which doesn’t feel like the build in SwiftUI APIs that we are used to, but maybe this is exactly what you are looking for. Let’s update our API in the next section.

//  ContentView.swift
import SwiftUI

struct ContentView: View {
var body: some View {
VStack {
MyCustomView(
"test",
childViewOne: HStack {
Text("child")
Text("one")
},
childViewTwo: HStack {
Text("child")
Text("two")
}
)
}
.padding()
}
}

#Preview {
ContentView()
}

The Built-in API Way

With this code we are using a function, and returning a view. We are passing our views in as parameters. This is what allows us to use the trailing closure syntax that gives us the feel of the built-in APIs. We can also see that this implementation is much less code that the easy way described above.

//  MySecondCustomView.swift
import SwiftUI

func MySecondCustomView<ChildOneContent: View, ChildTwoContent: View>(
_ text: LocalizedStringKey,
childViewOne: () -> ChildOneContent,
childViewTwo: () -> ChildTwoContent
) -> some View {
return VStack {
Text(text)
childViewOne()
childViewTwo()
}
}

The call site for this implementation can be seen in the code below. As you can tell, this matches much more closely to many built-in APIs like the VStack, Button, Picker, etc.

//  ContentView.swift
import SwiftUI

struct ContentView: View {
var body: some View {
VStack {
MySecondCustomView("test") {
HStack {
Text("child")
Text("one")
}
} childViewTwo: {
HStack {
Text("child")
Text("two")
}
}
}
.padding()
}
}

#Preview {
ContentView()
}

There are a few downsides to this option however, one of the reasons that we don’t typically use functions as views but instead use structs, is because structs are easy to destroy and recreate, there can be problems when a view doesn’t update when a value in the closure changes like could happen if we used functions for views. While this method looks much more built in, it isn’t recommended for production code.

If you got value from this article, please consider following me, 👏 clapping for this article, or sharing it to help others more easily find it.

If you have any questions on the topic or know of another way to accomplish the same task, feel free to respond to the post or share it with a friend and get their opinion on it. If you want to learn more about native mobile development, you can check out the other articles I have written here: https://medium.com/@jpmtech. If you want to see apps that have been built with native mobile development, you can check out my apps here: https://jpmtech.io/apps. Thank you for taking the time to check out my work!

--

--