I am trying to make a circle with dash lines. I am able to make lines in rectangle but I don't know how to make these in circle. Here is answer I got but it's in Objective-C: UIView Draw Circle with Dotted Line Border
Here is my code which makes a rectangle with dashed lines.
func addDashedBorder() {
let color = UIColor.red.cgColor
let shapeLayer:CAShapeLayer = CAShapeLayer()
let frameSize = self.frame.size
let shapeRect = CGRect(x: 0, y: 0, width: frameSize.width, height: frameSize.height)
shapeLayer.bounds = shapeRect
shapeLayer.position = CGPoint(x: frameSize.width/2, y: frameSize.height/2)
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = color
shapeLayer.lineWidth = 2
shapeLayer.lineJoin = CAShapeLayerLineJoin.round
shapeLayer.lineDashPattern = [6,3]
shapeLayer.path = UIBezierPath(roundedRect: shapeRect, cornerRadius: 5).cgPath
self.layer.addSublayer(shapeLayer)
}
Certainly you can just render your circular UIBezierPath
with the selected dash pattern:
class DashedCircleView: UIView {
private var shapeLayer: CAShapeLayer = {
let shapeLayer = CAShapeLayer()
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineWidth = 10
shapeLayer.lineCap = .round
shapeLayer.lineDashPattern = [20, 60]
return shapeLayer
}()
override init(frame: CGRect = .zero) {
super.init(frame: frame)
configure()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
override func layoutSubviews() {
super.layoutSubviews()
updatePath()
}
}
private extension DashedCircleView {
func configure() {
layer.addSublayer(shapeLayer)
}
func updatePath() {
let rect = bounds.insetBy(dx: shapeLayer.lineWidth / 2, dy: shapeLayer.lineWidth / 2)
let radius = min(rect.width, rect.height) / 2
let center = CGPoint(x: rect.midX, y: rect.midY)
let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: .pi * 2, clockwise: true)
shapeLayer.path = path.cgPath
}
}
That yields:
The problem with that approach is that it’s hard to get the dashed pattern to line up (notice the awkward dashing at the “3 o’clock” position). You can fix that by making sure that the two values of lineDashPattern
add up to some number that evenly divides into the circumference of the circle (e.g. 2π × radius):
let circumference: CGFloat = 2 * .pi * radius
let count = 30
let relativeDashLength: CGFloat = 0.25
let dashLength = circumference / CGFloat(count)
shapeLayer.lineDashPattern = [dashLength * relativeDashLength, dashLength * (1 - relativeDashLength)] as [NSNumber]
Alternatively, rather than using lineDashPattern
at all, you can instead keep a solid stroke and make the path
, itself, as a series of small arcs. That way I can achieve the desired dashed effect, but ensuring it’s evenly split into count
little arcs as we rotate from 0 to 2π:
class DashedCircleView: UIView {
private var shapeLayer: CAShapeLayer = {
let shapeLayer = CAShapeLayer()
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineWidth = 10
shapeLayer.lineCap = .round
return shapeLayer
}()
override init(frame: CGRect = .zero) {
super.init(frame: frame)
configure()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
override func layoutSubviews() {
super.layoutSubviews()
updatePath()
}
}
private extension DashedCircleView {
func configure() {
layer.addSublayer(shapeLayer)
}
func updatePath() {
let rect = bounds.insetBy(dx: shapeLayer.lineWidth / 2, dy: shapeLayer.lineWidth / 2)
let radius = min(rect.width, rect.height) / 2
let center = CGPoint(x: rect.midX, y: rect.midY)
let path = UIBezierPath()
let count = 30
let relativeDashLength: CGFloat = 0.25 // a value between 0 and 1
let increment: CGFloat = .pi * 2 / CGFloat(count)
for i in 0 ..< count {
let startAngle = increment * CGFloat(i)
let endAngle = startAngle + relativeDashLength * increment
path.move(to: CGPoint(x: center.x + radius * cos(startAngle),
y: center.y + radius * sin(startAngle)))
path.addArc(withCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
}
shapeLayer.path = path.cgPath
}
}
That yields:
You can use UIBezierPath(ovalIn:)
to create a circle path in a square view.
extension UIView {
func addDashedCircle() {
let circleLayer = CAShapeLayer()
circleLayer.path = UIBezierPath(ovalIn: bounds).cgPath
circleLayer.lineWidth = 2.0
circleLayer.strokeColor = UIColor.red.cgColor//border of circle
circleLayer.fillColor = UIColor.white.cgColor//inside the circle
circleLayer.lineJoin = .round
circleLayer.lineDashPattern = [6,3]
layer.addSublayer(circleLayer)
}
}
Set view background color .clear and fill color of the layer .white
class View1: UIViewController {
@IBOutlet weak var circleView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
circleView.backgroundColor = .clear//outside the circle
circleView.addDashedCircle()
}
}
Or using UIBezierPath(arcCenter:radius:startAngle:endAngle:clockwise:)
circleLayer.path = UIBezierPath(arcCenter: CGPoint(x: frame.size.width/2, y: frame.size.height/2),
radius: min(frame.size.height,frame.size.width)/2,
startAngle: 0,
endAngle: .pi * 2,
clockwise: true).cgPath
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With