So, this is the context: I have a set of custom shapes, say for instance ShapeA, ShapeB, ShapeC, ShapeD, ShapeE, ShapeF
, all of them conforming to a user defined protocol like this:
protocol HasNormalizedAABB: Shape {
func normalizedAABB() -> CGRect
}
It is very clear that HasNormalizedAABB
also requires conformance to Shape
, that in turn requires conformance to View
, so HasNormalizedAABB
concretions are also View
s.
Then somewhere else in the code there is an enum
that determines which of those shapes is visible at the moment, say for the sake of this example:
enum VisibleShape {
case A
case B
case C
case D
case E
case F
}
Now I need a way to map each possible state of this enum
to its corresponding HasNormalizedAABB
shape and organically apply a styling to whatever the rendered shape is. Keep in mind that I could need to do the same in 500 different views with 500 different styles applied to it. This makes it absolutely critical to create a way to parametrize the style instead of creating a different mapping for each style.
This is what I tried:
@ViewBuilder
static func EnumToShape(
enumState: VisibleShape,
transform: @escaping (any HasNormalizedAABB) -> some View
) -> some View {
switch enumState {
case .A:
transform(ShapeA())
case .B:
transform(ShapeB())
case .C:
transform(ShapeC())
case .D:
transform(ShapeD())
case .E:
transform(ShapeE())
case .F:
transform(ShapeF())
}
}
Which is supposed to be used as follows:
EnumToShape(enumState: myStateVariableOfTypeVisibleShape) {
$0
.stroke(.green, lineWidth: 2)
.shadow(color: .green, radius: 4)
}
Which causes Type 'any View' cannot conform to 'View'
I tried your code with some test examples but I got a different error. However, it was related to the fact the the parameter of the closure in EnumToShape
is of type any HasNormalizedAABB
. SwiftUI cannot work with that as it's not a specific type of view: it's any kind of view.
A workaround, or solution, would be to create a new wrapper type that conforms to HasNormalizedAABB
, and hence View
, that can wrap any kind of HasNormalizedAABB
.
Here is an example implementation:
struct AnyHasNormalizedAABB: HasNormalizedAABB {
private let wrapped: any HasNormalizedAABB
init(_ wrapped: any HasNormalizedAABB) {
self.wrapped = wrapped
}
func normalizedAABB() -> CGRect {
wrapped.normalizedAABB()
}
func path(in rect: CGRect) -> Path {
wrapped.path(in: rect)
}
}
@ViewBuilder func EnumToShape(
enumState: VisibleShape,
transform: @escaping (AnyHasNormalizedAABB) -> some View
) -> some View {
switch enumState {
case .A:
transform(.init(ShapeA()))
case .B:
transform(.init(ShapeB()))
case .C:
transform(.init(ShapeC()))
case .D:
transform(.init(ShapeD()))
case .E:
transform(.init(ShapeE()))
case .F:
transform(.init(ShapeF()))
}
}