M1L3 : Paths Challenge

Lesson 3 of Module 1 of the CodeWithChris Design Course introduces us to Path(). This element effectively allows you to “draw” a shape based on coordinates, a bit like a primitive CAD drawing (something I’m very used to).

It gets a bit complicated with where the drawing’s origin point is (you start drawing from 0,0 at the top-left, but the rotation point is the centre – but not the centre of the drawing/Path(), rather it’s the centre of the frame, so you need to pay special attention to the frame if you’re going to rotate the shape).

The “challenge” to this lesson is to draw a chevron next to a six-pointed star, a challenge that demonstrates there can be many ways to achieve the same ends. The star, in particular, can be drawn using .addLine() to every point, or it could be two triangles in a ZStack, or the same triangle with a second instance inverted/rotated and then using some method to offset the two.

I’d played around with the first two, considered the third option (pondering how best to offset them), and the challenge “solution” uses the third option.

struct ContentView: View {
    let chevronShape: Path = {
        return Path  { pen in
            pen.move(to: CGPoint(x:0, y:0))
            pen.addLine(to: CGPoint(x: 100, y: 200))
            pen.addLine(to: CGPoint(x: 0, y: 400))
            pen.addLine(to: CGPoint(x: 100, y: 400))
            pen.addLine(to: CGPoint(x: 200, y: 200))
            pen.addLine(to: CGPoint(x: 100, y: 0))
            pen.addLine(to: CGPoint(x: 0, y: 0))
            pen.closeSubpath()
        }
    }()
    let triangleShape: Path = {
        return Path  { pen in
            pen.move(to: CGPoint(x:0, y:0))
            pen.addLines([
                CGPoint(x: 100, y: 0),
                CGPoint(x: 50, y: 100),
                CGPoint(x: 0, y: 0)
            ])
            pen.closeSubpath()
        }
    }()
    var body: some View {
        VStack{
            HStack (alignment: .center){
                chevronShape
                    .fill(.blue)
                    .frame(width: 200, height: 400)
                ZStack {
                    triangleShape
                        .fill(.yellow)
                        .padding(.top, 15)
                    triangleShape
                        .fill(.yellow)
                        .rotationEffect(Angle(degrees: 180))
                        .padding(.bottom, 15)
                }
                .frame(width: 100, height: 100)
            }
        }        
    }
}

A path can consist of one / many .addLine() modifiers, or a single .addLines([]) modifier containing an array of points.

Note of caution: as mentioned before, we can’t use .fill() / .foregroundColor() if we want to use .stroke() for an outline of the shape. It’s one or the other.