SwiftUI Shapes
SwiftUI Shape
Shapes can be added to views by just creating them:.
Circles
GridRow { Circle() .fill(.yellow) Circle() .fill(.yellow) .border(.orange, width: 8) Circle() .stroke(.orange, lineWidth: 8) Circle() .stroke(.orange, lineWidth: 8) .background(Circle().fill(.yellow)) }.border(.green)

- One can fill a shape using the `.fill(...)` modifier.
- One can add a border using the `.border(...)` modifier.
- Note how the border is inside the shape's boundaries.
- One can define a stroke using the `.stroke(...)` modifier.
- Note how the stroke extends the shape's boundaries.
- Note also that a Shape can have either a fill or a stroke.
- (This changes in iOS 17.) To provide a fill and a stroke, define a background shape.
Rectangles
Unlike Circles, Rectangle have no restrictions on their dimensions. Rectangles are an example of Shapes, which fill their parent views.
The fourth Rectangle demonstates insets. First shapes can be inset from their parent's boundaries. In case of a RoundedRectangle, the corner radius of the inset shape is adjusted.
The overlay for the inset rectangle is not inset as the rectangle is. The overlay's boundaries correspond to the parent view's boundaries. Therefore, the translucent orange rectangle is larger than the yellow rounded rectangle.
GridRow { Rectangle() .fill(.yellow) RoundedRectangle(cornerSize: CGSize(width: 32, height: 16)) .fill(.yellow) RoundedRectangle(cornerRadius: 32) .fill(.yellow) RoundedRectangle(cornerRadius: 32) .inset(by: 16) .fill(.yellow) .overlay(content: { Rectangle() .inset(by: 8) .fill(.orange.opacity(0.3)) }) }.border(.green)

Ellipsis
An overlay is not automatically clipped by its parent view. It can be clipped by the parent view, but the clipped shape is then a Rectangle, not the original shape, which in this case would be an Ellipsis. Overlayed shapes can be inset, even by a negative value in which case they extend the parent shape's boundaries.
GridRow { Ellipse() .fill(.yellow) Ellipse() .fill(.yellow) .overlay(content: { Circle() .inset(by: -10) .fill(.orange) }) Ellipse() .fill(.yellow) .overlay(content: { Circle() .inset(by: -10) .fill(.orange) }) .clipped() Ellipse() .rotation(.radians(.pi / 16)) .fill(.yellow) .overlay(content: { Circle() .inset(by: -10) .fill(.orange) }) }.border(.green)

Custom Shapes
GridRow { Circle() .fill(.yellow) Star(n: 4, inner: 0.2) .fill(.yellow) Star(n: 8, inner: 0.4) .stroke(.red.opacity(0.5), style: StrokeStyle(lineWidth: 8.0, lineJoin: .round)) .background( Star(n: 8, inner: 0.4) .fill(.yellow)) Star(n: 16, inner: 0.7) .fill(.yellow) }.border(.green)
struct Star: Shape { var n: Int var inner: Double func path(in rect: CGRect) -> Path { let dim = min(rect.width, rect.height) let offset = CGPoint(x: rect.midX, y: rect.midY) let r = dim / 2.0 var p = Path() for i in 0 ..< n { let a1 = (2.0 * Double(i) + 0) / (2.0 * Double(n)) let a2 = (2.0 * Double(i) + 1) / (2.0 * Double(n)) let x1 = r * cos(a1 * 2.0 * .pi) let y1 = r * sin(a1 * 2.0 * .pi) let x2 = r * inner * cos(a2 * 2.0 * .pi) let y2 = r * inner * sin(a2 * 2.0 * .pi) if i == 0 { p.move(to: CGPoint(x: x1, y: y1)) } else { p.addLine(to: CGPoint(x: x1, y: y1)) } p.addLine(to: CGPoint(x: x2, y: y2)) } p.closeSubpath() p = p.applying(.init(translationX: offset.x, y: offset.y)) return p } }
