I’m trying to create a SwiftUI protocol called AdaptableView
, which allows conforming views to define two different layouts (compactBody
and expandedBody
) based on available width. Additionally, I want to allow adding shared modifications to these views via a body(content:)
method.
My protocol definition:
@MainActor
protocol AdaptableView: View {
associatedtype Compact: View
associatedtype Expanded: View
var windowClass: WindowClass { get }
@ViewBuilder var compactBody: Self.Compact { get }
@ViewBuilder var expandedBody: Self.Expanded { get }
}
extension AdaptableView {
var body: some View {
adaptableBody
}
private var adaptableBody: ConditionalContent<Self.Compact, Self.Expanded> {
switch windowClass {
case .compact:
.init(condition: .isTrue(compactBody))
case .expanded:
.init(condition: .isFalse(expandedBody))
}
}
}
This works fine for selecting between compactBody and expandedBody, but I also want to allow shared customization for both states.
Adding a body(content:) Method
I introduced an additional requirement:
associatedtype AdaptableBody: View
@ViewBuilder func body(content: ConditionalContent<Self.Compact, Self.Expanded>) -> Self.AdaptableBody
To make it optional, I added a default implementation:
extension AdaptableView {
var body: some View {
body(content: adaptableBody)
}
func body(content: ConditionalContent<Compact, Expanded>) -> some View {
content
}
}
This compiles, but if I try to override body(content:) in a conforming view, it never gets called.
struct ContentView: AdaptableView {
@Environment(\.windowClass) var windowClass
var compactBody: some View {
Text("compact")
}
var expandedBody: some View {
Text("expanded")
}
func body(content: ConditionalContent<Compact, Expanded>) -> some View {
content
}
}
This compiles without errors as long as the default implementation of body(content:) exists. However, the custom implementation in ContentView is never called.
If I delete the default implementation, I start getting errors:
- “Unsupported recursion for reference to type alias ‘Compact’ of type ‘ContentView’”
- If I change Compact and Expanded to Self.Compact and Self.Expanded, I get: “Type ‘ContentView’ does not conform to protocol ‘AdaptableView’”
Why does my custom body(content:) implementation never get called?|
Why does removing the default implementation cause conformance issues?|