Custom Shape in SwiftUI

DevTechie Inc
Jun 11, 2022

Photo by Shubham Dhage on Unsplash

If you are looking to build custom shape, SwiftUI’s shape protocol makes it super easy. You get access to path and rectangle in which shape is drawn so your shape can compute relative size while drawing the path.

Let’s create a diamond shape, which we will convert into a zig zag shape(well sorta like zig zag sale sign). Inspiration for creating this shape came from an ad I watched on TV where there was a sale sign 😅

In case you are wondering, here is what the zig zag sale sign looks like:

Our final output will look like this(gif reduced the animation but will look good in simulator, I promise 😃):

We will start with a diamond shape struct which will conform to Shape protocol. Only requirement for shape protocol is to implement path(in rect:) function. Path function gives us access to rect and we can draw custom path as shown below:

struct Diamond: Shape {
    func path(in rect: CGRect) -> Path {
        Path() { p in
            p.move(to: CGPoint(x: rect.midX, y: rect.minY))
            p.addLine(to: CGPoint(x: rect.midX, y: rect.minY))
            p.addLine(to: CGPoint(x: rect.maxX, y: rect.midY))
            p.addLine(to: CGPoint(x: rect.midX, y: rect.maxY))
            p.addLine(to: CGPoint(x: rect.minX, y: rect.midY))
Next we will create ZigZagView and we will repeat our Diamond shape with a rotation angle to give them a zig zag shape.

struct ZigZagView: View {
    @State private var rotation: Double = 0
    var body: some View {
        ForEach(0...10, id: \.self) { idx in 
                .frame(height: 200)
                .rotationEffect(.degrees(Double(idx * 30)))
Lastly, we will use our ZigZagView and add overlay text, scale and rotation animation.

struct CustomShapeView: View {
    @State private var scale = false
    @State private var rotation: Double = 0
    var body: some View {
        ZStack {
                        .font(.system(size: 78))
                        .scaleEffect(scale ? 0.5 : 1)
                .frame(width: 400, height: 400)
                .scaleEffect(scale ? 0.5 : 1)
                .animation(.easeInOut.speed(0.1).repeatForever(autoreverses: true), value: scale)
                .onAppear { 
                    rotation = -30
Final output:

With that we have reached the end of this article. Thank you once again for reading. Don’t forget to subscribe to our weekly newsletter at