When trying to use a generic type to init/add a view to another SwiftUI view, I get the error Type 'T' has no member 'init'
. How can this be solved?
I guess the problem is, that View
is just a protocol which only requires a body
property and nothing more. But what type could be used instead?
Simple Example:
Trying to use TrippleView<T: View>
which should create/show three views of type T
. Adding views (RedRectView
or BlueCircleView
) is no problem. Passing these views as generic parameter fails:
struct SomeView: View {
var body: some View {
TrippleView<RedRectView>()
TrippleView<BlueCircleView>()
}
}
struct TrippleView<T: View>: View {
var body: some View {
VStack {
// Does NOT work: Type 'T' has no member 'init'
T()
T()
T()
// Works fine
// RedRectView()
// BlueCircleView()
// RedRectView()
}
}
}
struct RedRectView: View {...}
struct BlueCircleView: View {...}
EDIT:
The TrippleView
is of course just an example. I would like to use the generic view just as any other generic type: To a common base "type" in different scenarios.
For example two versions of a list view which use a generic CellView
to display the same data in two different styles / layouts.
CodePudding user response:
You need a ViewBuilder inside your struct to initialize the view. Here's an example,
Struct that takes in generic view and returns a view.
struct TripleView<T: View>: View {
// simple example that takes in one parameter.
var someView: T
init(@ViewBuilder someView: () -> T) {
self.someView = someView()
}
var body: some View {
// You can modify your viewes here.
someView
.foregroundColor(.red)
someView
.foregroundColor(.blue)
someView
.foregroundColor(.green)
}
}
Or you can take in multiple parameters
struct TripleViewsWithParam<T1: View, T2: View, T3: View>: View {
// you can take as many parameters as you want.
var someView1: T1
var someView2: T2
var someView3: T3
init(@ViewBuilder someView1: () -> T1, @ViewBuilder someView2: () -> T2, @ViewBuilder someView3: () -> T3) {
self.someView1 = someView1()
self.someView2 = someView2()
self.someView3 = someView3()
}
var body: some View {
VStack {
someView1
someView2
someView3
}
}
}
Calling the struct in your main view
struct SomeView: View {
var body: some View {
VStack{
TripleView {
Text("Triple View Example")
}
TripleViewsWithParam(
someView1: {
Text("View 1")
}, someView2: {
Text("View 2")
}, someView3: {
Text("View 3")
}
)
}
}
}