I've just learned that the standard Apple .round
endcap
let l = CAShapeLayer()
l.path = .. just a straight line, say 50 long
l.lineWidth = say "3.1" in the example shown here
l.lineCap = .round
is not very apparently round in some cases, see images.
I appreciate that I could build my own line line and fill it.
But is there a way to perhaps subclass "endcap" in some way?
It would be magic if you could say = .myHappyEndcapMode
How do we fix this?
You can see how far off it is here:
Further info:
The non-round visual look appears to arise in the case of:
There is no way to “subclass” the cap shape. You will have to manually construct the outline of the shape if you want a different cap shape.
The round cap is already exactly as circular as a circle created with CGPath(ellipseIn:)
.
Here's a round-capped line drawn on top of a circle of slightly larger radius, zoomed 8x:
The curvature of the line cap starts exactly at the horizontal center of the circle.
Here's the code:
import UIKit
import PlaygroundSupport
let lineWidth: CGFloat = 20
let circleRadius = lineWidth / 2 + 1
let lineLayer = CAShapeLayer()
lineLayer.position = .init(x: 30, y: 30)
let path = CGMutablePath()
path.move(to: .zero)
path.addLine(to: .init(x: 30, y: 0))
lineLayer.path = path
lineLayer.lineWidth = lineWidth
lineLayer.lineCap = .round
lineLayer.strokeColor = UIColor.gray.cgColor
lineLayer.fillColor = nil
let circleLayer = CAShapeLayer()
circleLayer.position = lineLayer.position
circleLayer.path = CGPath(ellipseIn: CGRect.zero.insetBy(dx: -circleRadius, dy: -circleRadius), transform: nil)
circleLayer.fillColor = UIColor.blue.cgColor
let view = UIView(frame: .init(x: 0, y: 0, width: 100, height: 80))
view.layer.backgroundColor = UIColor.white.cgColor
view.layer.addSublayer(circleLayer)
view.layer.addSublayer(lineLayer)
PlaygroundPage.current.liveView = view