I've written a simple shape container that can be styled using an environment value.
struct CoolShape: Shape {
@Environment(\.coolShapeStyle) var coolShapeStyle
func path(in rect: CGRect) -> Path {
coolShapeStyle.path.path(in: rect)
}
}
I then added some sample styles to style the shape and also created some utility functions to make it easy to add the style.
protocol CoolShapeStyle {
var path: Path { get }
}
struct CoolCircleStyle: CoolShapeStyle {
let path = Path(ellipseIn: CGRect(
x: 0, y: 0,
width: 100, height: 100
))
}
struct CoolSquareStyle: CoolShapeStyle {
let path = Path(CGRect(
x: 0, y: 0,
width: 100, height: 100
))
}
extension CoolShapeStyle where Self == CoolCircleStyle {
static var circle: Self { Self() }
}
extension CoolShapeStyle where Self == CoolSquareStyle {
static var square: Self { Self() }
}
struct CoolShapeStyleEnvironmentKey: EnvironmentKey {
static let defaultValue: CoolShapeStyle = CoolCircleStyle()
}
extension EnvironmentValues {
var coolShapeStyle: CoolShapeStyle {
get { self[CoolShapeStyleEnvironmentKey.self] }
set { self[CoolShapeStyleEnvironmentKey.self] = newValue }
}
}
extension View {
func coolShapeStyle(_ coolShapeStyle: CoolShapeStyle) -> some View {
environment(\.coolShapeStyle, coolShapeStyle)
}
}
I then proceed to create the view as one would do normally, which works fine, all until I also add a fill or stroke to the shape.
// This works fine
CoolShape()
.coolShapeStyle(.circle)
// This creates a warning
CoolShape()
.fill(Color.red)
.coolShapeStyle(.square)
I'll then get the environment value error:
Accessing Environment's value outside of being installed on a View. This will always read the default value and will not update.
This is very odd, as a Shape
and also the InsettableShape
conform to View
, yet the path(in:)
function appears to be run at a different time. Is there any way I can fix this?