NEW: My new book Pro SwiftUI is out now – level up your SwiftUI skills today! >>

SOLVED: Day 43 Question

Forums > 100 Days of SwiftUI

Hello guys,

I practiced drawing and I have a question: Why the right line of the arrow goes edge-to-edge?

Also why without .stroke() I can't see anything?

Thank you.

import SwiftUI

struct Arrow: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()

        path.move(to: CGPoint(x: rect.width / 2, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.width / 4, y: rect.height / 4))
        path.move(to: CGPoint(x: rect.width / 2, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.width * 4, y: rect.height * 4))
        path.move(to: CGPoint(x: rect.width / 2, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.midX, y: rect.maxY))
        path.closeSubpath()

        return path
    }
}

struct ArrowView: View {
    var body: some View {

        Arrow()
            .stroke()
    }
}

struct ArrowView_Previews: PreviewProvider {
    static var previews: some View {
        ArrowView()
    }
}

   

@andrea wants us to be the compiler!

I practiced drawing and I have a question: Why does the right line of the arrow go edge-to-edge?

This is a great chance for you to practice being the compiler!

Grab a piece of paper and a pencil, the FOLLOW YOUR DIRECTIONS exactly as you have them.

// -------- LEFT SIDE OF ARROW --------------------
// First move your pencil HALFWAY across the paper (width / 2) 
// and to the top of the page
        path.move(to: CGPoint(x: rect.width / 2, y: rect.minY))

// Next, drag your pencil to a point that's 1/4 of the way      
// from the leading edge and 1/4 of the way down from the top.
        path.addLine(to: CGPoint(x: rect.width / 4, y: rect.height / 4))

// Pick UP your pencil and put it back at this point
        path.move(to: CGPoint(x: rect.width / 2, y: rect.minY))

// -------- RIGHT SIDE OF ARROW ----------------
// Now where do you want to draw the line to? 
// This part requires you to do MATH.
// Calculate the X coordinate.
// Calculate the Y coordinate.
        path.addLine(to: CGPoint(x: rect.width * 4, y: rect.height * 4))

// Final path
        path.move(to: CGPoint(x: rect.width / 2, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.midX, y: rect.maxY))

Solving your arrow problem

I didn't see the problem immediately. These were the steps I followed to solve your problem.

But, I don't think I should just give you the answer.
Instead, I gave you a technique that you should learn to help you with other problems you'll encounter.

BE THE COMPILER. Follow your own directions.

Keep coding!

Also, I encourage you to put LOTS OF COMMENTS INTO YOUR CODE.

   

@andrea asks a language design question:

why do you need .stroke() to see the shape?

Others might say "this is a feature, not a bug."

Probably way before iOS, iPhones, and iPads back when programs were only written for the MacOS, someone looked how to best optimize the way shapes and images were drawn to the screen. Processors weren't the fastest. So languages took optimization seriously. These decisions were made long ago.

As you can see, you first must layout all the edges of your path describing when to put the "pen" down on the paper, and when to "draw" a line from one point to the next.

Then, when the entire path is defined, you can select how those lines are drawn. There are many, many options that you've not even encountered yet. Think of these options as the path's "ink".

Do you want dashed lines?
Do you want dotted lines?
Do you want thick, blue lines?
Do you want transparent yellow lines?
Do you want rounded corners? or Sharp, angular corners?

Once you have your shape defined, you can also define the path's look and feel. When you have all this decided, you make the shape appear by finally adding "ink" to your path.

   

@Obelix

I changed the coordinates and it works. Please can you tell me your previous solution on the math question?

I have difficulties on math :(

My code:

import SwiftUI

struct Arrow: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()

        path.move(to: CGPoint(x: rect.midX, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.minX, y: rect.midY))
        path.move(to: CGPoint(x: rect.midX, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.midY))
        path.move(to: CGPoint(x: rect.midX, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.midX, y: rect.maxY * 1.5))

        /*
        path.move(to: CGPoint(x: rect.width / 2, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.width / 4, y: rect.height / 4))
        path.move(to: CGPoint(x: rect.width / 2, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.width * 0.8, y: rect.height / 4))
        path.move(to: CGPoint(x: rect.width / 2, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.midX, y: rect.maxY))
*/
        return path
    }
}

struct ArrowView: View {
    var body: some View {

        Arrow()
            .stroke()
            .frame(width: 300, height: 300)
    }
}

struct ArrowView_Previews: PreviewProvider {
    static var previews: some View {
        ArrowView()
    }
}

   

Break your big problem into smaller, solvable problems.

// -------- BIG PROBLEM ----------------
// Now where do you want to draw the line to? 
// This part requires you to do MATH.
// Calculate the X coordinate.
// Calculate the Y coordinate.
path.addLine(to: CGPoint(x: rect.width * 4, y: rect.height * 4))

// ------------ smaller problem -------------
let xCoordinate = rect.width * 4
let yCoordinate = rect.height * 4
let rightSideOfArrowPoint = CGPoint(x: xCoordinate, y: yCoordinate)
path.addLine(to: rightSideOfArrow)

All the drawing takes place inside of a rectangle, which you defined as rect in this code

func path(in rect: CGRect) -> Path {

As an example, let's say your rectangle is 500 pixels wide and 500 pixels tall. You start the right side of your arrow head at this point.

// Pick UP your pencil and put it back at this point
        path.move(to: CGPoint(x: rect.width / 2, y: rect.minY))

This point is halfway between the left and right edges of the rectangle, (rect.width / 2)-> (500 / 2) -> (250 pixels).
This point is also at the very top of the rectangle, (rect.minY) -> (0 pixels).

Now you want to draw a line to the rightSideOfArrowPoint.

This is how you defined the xCoordinate. (rect.width x 4) -> (500 x 4) -> (2000 pixels)
This is how you defined the yCoordinate. (rect.height x 4) -> (500 x 4) -> (2000 pixels)

Consequently, you draw a line from the coordinate (250, 0) all the way to (2000, 2000). This point is waaaaaaaaaaaay outside of the rectangle.

This is why your first arrow wasn't drawn correctly.

   

Hacking with Swift is sponsored by Play

SPONSORED Play is the first native iOS design tool created for designers and engineers. You can install Play for iOS and iPad today and sign up to check out the Beta of our macOS app with SwiftUI code export. We're also hiring engineers!

Click to learn more about Play!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.