So I have this TestView
which accepts headerContent
and bodyContent
,
struct TestView<Content: View>: View {
let headerContent: (() -> Content)? = nil
let bodyContent: () -> Content
var body: some View {
VStack {
headerContent?()
bodyContent()
}
}
}
And I use it as,
struct ContentView: View {
var body: some View {
TestView {
Text("Body Content")
}
}
}
Now, how do I pass headerContent
? I tried doing,
struct ContentView: View {
var body: some View {
TestView(headerContent: {
Text("HeaderContent")
}) {
Text("BodyContent")
}
}
}
I get error,
Extra arguments at positions #1, #2 in call
Generic parameter 'Content' could not be inferred
CodePudding user response:
Change your optional variable from let
to var
.
When you define a variable using let
keyword then you can't change it. In your example, you have set nil as constant for a headerContent
.
struct TestView<Content: View>: View {
var headerContent: (() -> Content)? = nil
let bodyContent: () -> Content
You can also use let
with init
struct TestView<Content: View>: View {
let headerContent: (() -> Content)?
let bodyContent: () -> Content
init(headerContent: (() -> Content)? = nil, bodyContent: @escaping () -> Content) {
self.headerContent = headerContent
self.bodyContent = bodyContent
}
CodePudding user response:
Just make it var
(ie. changeable) instead of let
, like
struct TestView<Content: View>: View {
var headerContent: (() -> Content)? = nil // << here !!
...
CodePudding user response:
Way1:
Here is a way, but you would get issue and error if your headerView type be deferent than the body Content! E.g. Circle and Text. I solved this issue in my second Way:
struct TestView<Content: View>: View {
@ViewBuilder let headerContent: (() -> Content)?
@ViewBuilder let bodyContent: () -> Content
init(headerContent: (() -> Content)? = nil, bodyContent: @escaping () -> Content) {
self.headerContent = headerContent
self.bodyContent = bodyContent
}
var body: some View {
return VStack {
headerContent?()
bodyContent()
}
}
}
Way2:
Here is the right way for you:
struct TestView<BodyContent: View, HeaderContent: View>: View {
@ViewBuilder let headerContent: () -> HeaderContent
@ViewBuilder let bodyContent: () -> BodyContent
init(headerContent: @escaping () -> HeaderContent, bodyContent: @escaping () -> BodyContent) {
self.headerContent = headerContent
self.bodyContent = bodyContent
}
init(bodyContent: @escaping () -> BodyContent) where HeaderContent == EmptyView {
self.headerContent = { EmptyView() }
self.bodyContent = bodyContent
}
var body: some View {
return VStack {
headerContent()
bodyContent()
}
}
}
Use case:
struct ContentView: View {
var body: some View {
TestView(headerContent: {
Circle().fill(Color.red).frame(width: 25, height: 25)
}, bodyContent: {
Text("Hello, World!")
})
TestView(bodyContent: {
Text("Hello, World!")
})
}
}