I’m starting with Swift (coming from front-end) with test projects and have a question about view and view builders
For reference: in a front-end framework Vue.js there is a concept of slots and slot props https://vuejs.org/guide/components/slots.html#scoped-slots
Same goes for Svelte https://svelte.dev/docs/special-elements#slot and also same functionality can be achieved in React
For example I have some generic list that has some basic layout and makes some logic (filtration, sorting etc) inside and I want to use it to pass a list and display list items however I want, and if I won’t provide a builder, there will be some default view that is specified inside that list
Is there any way to achieve such functionality in SwiftUI/UIKit?
What I’ve tried to do is something like the next code, I simplified it to show the general idea
import SwiftUI
struct ListTestView\<T: Hashable, Content: View\>: View {
private let items: \[T\]
private let listItemBuilder: (ListItemBuilderParams) -\> Content
init(
_ list: [T],
@ViewBuilder listItem: @escaping (_ params: ListItemBuilderParams) -> Content
) {
self.items = list
self.listItemBuilder = listItem
}
var body: some View {
VStack {
ForEach(filteredItems, id: \.self) { item in
listItemBuilder(.init(item1: item, item2: item, item3: item)) // ?? Text(String(item))
}
}
}
private var filteredItems: [T] {
// ...some filtration
return items
}
struct ListItemBuilderParams {
let item1: T
let item2: T
let item3: T
// ... and possible more
}
}
struct ViewWithList: View {
var body: some View {
ListTestView(\[1, 2, 3, 4\]) { params in
Text(String(params.item1))
Button(String(params.item2)) {}
Text(String(params.item3))
}
}
}
But it won’t compile because in ViewWithList I get an error Generic parameter 'Content' could not be inferred
But it compiles if I pass all the params as plain arguments list, without a struct, but it may get really messy because there is no way to omit some specific arguments and I have to list them all in closure
import SwiftUI
struct ListTestView<T: Hashable, Content: View>: View {
private let items: [T]
private let listItemBuilder: (T, T, T) -> Content
init(
_ list: [T],
@ViewBuilder listItem: @escaping (T, T, T) -> Content
) {
self.items = list
self.listItemBuilder = listItem
}
var body: some View {
VStack {
ForEach(filteredItems, id: \.self) { item in
listItemBuilder(item, item, item) // ?? Text(String(item))
}
}
}
private var filteredItems: [T] {
// ...some filtration
return items
}
}
struct ViewWithList: View {
var body: some View {
ListTestView([1, 2, 3, 4]) { item1, item2, item3 in
Text(String(item1))
Button(String(item2)) {}
Text(String(item3))
}
}
}




