I am currently learning SwiftUI, and I ran into a problem.
In the below code I have two initialisers. The first one works (assuming I comment out the second one long enough to test the code). The second one does not. It throws a compiler error saying "Cannot assign value of type 'some View' to type 'Content'."
What am I doing wrong here? I am able to successfully call the first initialiser from outside the struct using Infobox() { Text("Some Text") }, which seems to me to be the exact same syntax I'm using when trying to call it from the second initialiser. No matter how much I google, I can't seem to figure this one out.
I'd very much appreciate any help you can give.
struct Infobox<Content>: View where Content: View {
let content: Content
var body: some View {
content
}
init(@ViewBuilder _ content: @escaping () -> Content) {
self.content = content()
}
init(withHeader headerText: String, @ViewBuilder _ content: @escaping () -> Content) {
self.init() {
VStack(alignment: .leading) {
Text(headerText)
.font(.headline)
}
content()
}
}
}
}
What you mean is probably this:
init<T: View>(withHeader headerText: String, @ViewBuilder _ content: @escaping () -> T)
where Content == VStack<TupleView<(Text, T)>> {
self.init {
VStack(alignment: .leading) {
Text(headerText)
.font(.headline)
content()
}
}
}
The view created by this initialiser will always be of the form (And yes)
InfoBox<VStack<TupleView<(Text, SomeOtherView)>>>
In other words, this init is deciding what Content should be. So it is only applicable to InfoBoxes with Content == ThatLongTypeName, hence the constraint.
Note that the caller can specify the type of SomeOtherView, but that is not Content! Content is VStack<TupleView<(Text, SomeOtherView)>>. Therefore, an extra generic parameter is added, and the closure return type is changed.
IMO, it'd be much simpler if you just did this:
struct Infobox<Content>: View where Content: View {
let content: () -> Content
let headerText: String
var body: some View {
VStack(alignment: .leading) {
if !headerText.isEmpty {
Text(headerText)
.font(.headline)
}
content()
}
}
// note the optional parameter here
init(withHeader headerText: String = "", @ViewBuilder _ content: @escaping () -> Content) {
self.content = content
self.headerText = headerText
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With