I am trying to draw a circle in SwiftUI using a Shape, Geometry reader and Path, I want a shadow to sit right underneath the circle but the shadow is coming out offset and I can't seem to get it to draw where it should:

struct ContentView: View {
var body: some View {
return GeometryReader { geometry in
VStack(alignment: .center) {
BackgroundRing()
.stroke(Color.red, style: StrokeStyle(lineWidth: geometry.size.width < geometry.size.height ? geometry.size.width / 12.0 : geometry.size.height / 12))
.padding()
.shadow(color: .gray, radius: 1.0, x: 0.0, y: 0.0)
}
}
}
}
struct BackgroundRing : Shape {
func path(in rect: CGRect) -> Path {
var path: Path = Path()
let radiusOfRing: CGFloat = (rect.width < rect.height ? rect.width/2 - rect.width / 12 : rect.height/2 - rect.height / 12)
path.addRelativeArc(center: CGPoint(x: rect.width/2, y: rect.height/2),
radius: radiusOfRing,
startAngle: Angle(radians: 0.0),
delta: Angle(radians: Double.pi * 2.0 ))
return path
}
}
OK So I seem to have managed to fix the problem. There is something going on with the width / heigh that interacts with the code to calculate the location of the shadow - the shadow position seems to come from the frame dimensions rather than the Shape.
Adding
.aspectRatio(contentMode: .fit)
fixes the problem
Additionally, it seems that .shadow automatically sets the default offset to the same value as the radius, so to get a real offset of 0.0 you have to set it relative to the radius, like this:
.shadow(radius: 10.0, x: -10.0, y: -10.0)
Looks to me like a bug, but this work around solves it:

import SwiftUI
struct ContentView: View {
var body: some View {
return GeometryReader { geometry in
VStack(alignment: .center) {
BackgroundRing()
.stroke(Color.red,
style: StrokeStyle(lineWidth: geometry.size.width < geometry.size.height ? geometry.size.width / 12.0 : geometry.size.height / 12))
.shadow(radius: 30.0, x: -30.0, y: -30.0)
.aspectRatio(contentMode: .fit)
}
}
}
}
struct BackgroundRing : Shape {
func path(in rect: CGRect) -> Path {
var path: Path = Path()
let radiusOfRing: CGFloat = (rect.width < rect.height ? rect.width/2 - rect.width / 12 : rect.height/2 - rect.height / 12)
path.addRelativeArc(center: CGPoint(x: rect.width/2, y: rect.height/2), // <- this change solved the problem
radius: radiusOfRing,
startAngle: Angle(radians: 0.0),
delta: Angle(radians: Double.pi * 2.0 ))
return path
}
}
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