I’ve created a custom layout and since they are available on iOS >=16 I would like to use a @ViewBuilder to hide it with its fallback code:
So instead of having this in my View:
if #available(iOS 16, *) {
CustomLayout() {
Text("Hello, World!")
}
} else {
VStack(alignment: .leading) {
Text("Hello, World!")
}
}
I would like to hide it behind:
struct ProportionalView<Content: View>: View {
@ViewBuilder var content: () -> Content
var body: some View {
if #available(iOS 16.0, *) {
CustomLayout() { content } // 👈 Here is what's wrong
} else {
VStack(alignment: .leading, content: content)
}
}
}
//Then use it in the View as:
ProportionalView {
Text("Hello, World!")
}
Pretty standard SwiftUI practic. But it looks like the Custom Layout doesn’t work this way. While it accepts type View in SwiftUI View code, it doesn’t accept it here and gives an error: "Type '() -> Content' cannot conform to 'View'". And if I wrap it in Group { } an error No exact matches in reference to static method 'buildExpression'
Is there a way to force Custom Layout accept a View in @ViewBuilder?
>Solution :
You declared content like this:
@ViewBuilder var content: () -> Content
which means it is a function. To get a View, you have to actually call the function:
CustomLayout() { content() }
// ^^ add parens to call the function
But for the code you posted, it’s probably better to change content to not be a function, as it will be slightly more efficient due to not storing an escaping closure on the heap:
struct ProportionalView<Content: View>: View {
@ViewBuilder var content: Content
// ^^^^^^^ change type
var body: some View {
if #available(iOS 16.0, *) {
CustomLayout() { content }
} else {
VStack(
alignment: .leading,
content: { content }
// ^^^^^^^^^^^ wrap this use in a function
)
}
}
}