Search code examples
iosswiftuibezierpathcashapelayer

Increasing UIBezierPath linewidth changes geometry...?


I've created a circular gauge as a visual indicator for a timer. There are multiple segments of the gauge to indicate different stages of the timer. Image here

The problem is that when I add a line width to the paths, the math no longer adds up. For example, the blue and red segment in the image above should be the same size (same % of the circle), but because of the line width, the red is overlapping the blue and, likewise, the grey segment overlaps the blue (I am drawing the segments counter clockwise)—so the blue appears smaller. I know that my segments are created correctly, because if I set the linewidth to 1.0, I get the following, correct result. Image here

If anyone has any insights on this, that would be great.

Code to give context:

 //create path
 let circularPath = UIBezierPath(arcCenter: view.center, radius: 100, startAngle: -CGFloat.pi/2, endAngle: 3*CGFloat.pi/2, clockwise: true)

 //create segments - this is in a loop that adjusts start/end for all the segments
 var tempShapeLayer = CAShapeLayer()
 tempShapeLayer.path = circularPath.cgPath
 tempShapeLayer.lineWidth = 10
 tempShapeLayer.fillColor = UIColor.clear.cgColor
 tempShapeLayer.lineCap = CAShapeLayerLineCap.square
 tempShapeLayer.strokeStart = start
 tempShapeLayer.strokeEnd = end
 //next simply add some colors and add to view

Solution

  • You are using the wrong line cap style. You should be using .butt.

    The different styles of line cap can be found in CGLineCap.

    • butt:

      A line with a squared-off end. Core Graphics draws the line to extend only to the exact endpoint of the path.

    • square:

      A line with a squared-off end. Core Graphics extends the line beyond the endpoint of the path for a distance equal to half the line width.

    Using a square cap will cause the line to be a tiny bit longer on both sides than it should. For all segments except the last one drawn, this is not a problem, because their endpoints will be covered by other segments. But for the last segment drawn, it will appear longer than it should on both sides.

    You should use .butt for the line cap style.