[SOLVED] Swift draw alternating dashed and dotted line with UIBezierPath

Issue

This Content is from Stack Overflow. Question asked by narner

I’m attempting to draw a line with a UIBezierPath that alternates between dots and dashes. Here’s my code so far:

 func drawAlternatingDashesAndDots() {
        let path = UIBezierPath()
        path.move(to: CGPoint(x: 10,y: 10))
        path.addLine(to: CGPoint(x: 290,y: 10))
        path.lineWidth = 8

        let dots: [CGFloat] = [0.001, path.lineWidth * 2]
        path.setLineDash(dots, count: dots.count, phase: 0)

        for i in 0...10 {
            if i % 2 == 0 {
              // Even Number
                path.lineCapStyle = CGLineCap.round

            } else {
              // Odd Number
                path.lineCapStyle = CGLineCap.square
            }
        }
        UIGraphicsBeginImageContextWithOptions(CGSize(width:300, height:20), false, 2)
        UIColor.white.setFill()
        UIGraphicsGetCurrentContext()!.fill(.infinite)
        UIColor.black.setStroke()
        path.stroke()
        
        let image = UIGraphicsGetImageFromCurrentImageContext()
        dashDotDashLineView.image = image
        UIGraphicsEndImageContext()
    }

However, in my image view, only dots are rendered:

enter image description here

I’m probably misunderstanding something about how UIBezierPath works; any help appreciated!



Solution

The UIBezierPath documentation explains the meaning of the pattern argument:

A C-style array of floating point values that contains the lengths (measured in points) of the line segments and gaps in the pattern. The values in the array alternate, starting with the first line segment length, followed by the first gap length, followed by the second line segment length, and so on.

In your code, 0.001 is the first value in the pattern, so it is a line segment length, and is small enough to be drawn as a dot. The second value in the pattern is path.lineWidth * 2, so it is a gap length, which is the distance between the dots.

If you want to alternate dots and dashes, you have to pass a pattern containing four numbers: a line segment length, a gap, another line segment length, and another gap.

let dots: [CGFloat] = [
    0.001,              // dot
    path.lineWidth * 2, // gap
    path.lineWidth * 2, // dash
    path.lineWidth * 2, // gap
]


This Question was asked in StackOverflow by narner and Answered by rob mayoff It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

people found this article helpful. What about you?