It\'s easy to draw a dashed line with UIKit. So:
CGFloat dashes[] = {4, 2};
[path setLineDash:dashes count:2 phase:0];
[path stroke];
Working fine with the below code,
layer.path = linePath.cgPath
layer.lineWidth = 3
layer.lineDashPattern = [1,layer.lineWidth*2] as [NSNumber]
layer.lineCap = "round"
Not a full answer, just a very important gotcha that James P raised in a comment on the favourite answer:
He wrote:
I've found setting the on length to 0.01 gives you a circular dot, whereas they are slightly elongated when using 0.
For example,
let dashes: [CGFloat] = [0.001, path.lineWidth * 2]
Hey it's maybe too late to answer on that question. but if you agree I would like to share an easy way to resolve that to the developers that will maybe face that problem in the future. so I guess that the easiest solution using @IBDesignable. You need just to create that class
import UIKit
@IBDesignable class DottedVertical: UIView {
@IBInspectable var dotColor: UIColor = UIColor.red
@IBInspectable var lowerHalfOnly: Bool = false
override func draw(_ rect: CGRect) {
// say you want 8 dots, with perfect fenceposting:
let totalCount = 8 + 8 - 1
let fullHeight = bounds.size.height
let width = bounds.size.width
let itemLength = fullHeight / CGFloat(totalCount)
let path = UIBezierPath()
let beginFromTop = CGFloat(0.0)
let top = CGPoint(x: width/2, y: beginFromTop)
let bottom = CGPoint(x: width/2, y: fullHeight)
path.move(to: top)
path.addLine(to: bottom)
path.lineWidth = width
//DASHED SIMPLE LINE
//let dashes: [CGFloat] = [itemLength, itemLength]
//path.setLineDash(dashes, count: dashes.count, phase: 0)
// for ROUNDED dots, simply change to....
let dashes: [CGFloat] = [0.0, itemLength * 1.1]
path.lineCapStyle = CGLineCap.round
path.setLineDash(dashes, count: dashes.count, phase: 0)
dotColor.setStroke()
path.stroke()
}
}
And then append it to your view in the storyboard like that
Once you've done you cold customize the space between the layers from this line let dashes: [CGFloat] = [0.0, itemLength * 1.1]
--> Line 39 in the DottedVertical class.
or if you want to customize the width of the layer you need just to edit your line view width from your storyboard
Set the line cap style to round and set the “on” length to a tiny number.
Swift playground example:
import UIKit
import PlaygroundSupport
let path = UIBezierPath()
path.move(to: CGPoint(x:10,y:10))
path.addLine(to: CGPoint(x:290,y:10))
path.lineWidth = 8
let dashes: [CGFloat] = [0.001, path.lineWidth * 2]
path.setLineDash(dashes, count: dashes.count, phase: 0)
path.lineCapStyle = CGLineCap.round
UIGraphicsBeginImageContextWithOptions(CGSize(width:300, height:20), false, 2)
UIColor.white.setFill()
UIGraphicsGetCurrentContext()!.fill(.infinite)
UIColor.black.setStroke()
path.stroke()
let image = UIGraphicsGetImageFromCurrentImageContext()
let view = UIImageView(image: image)
PlaygroundPage.current.liveView = view
UIGraphicsEndImageContext()
Result:
For objective-C, using the same example class as in the question, simply add
CGContextSetLineCap(cx, kCGLineCapRound);
before the call to CGContextStrokePath
, and change the ra
array values to match my Swift code.