当然,您可以使用所选的虚线模式渲染圆形
UIBezierPath
:
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
}
}
这会产生:
这种方法的问题在于很难使虚线图案对齐(请注意“3点钟”位置的尴尬虚线)。您可以通过确保lineDashPattern
的两个值加起来等于某个能够整除圆周长(例如2π×半径)的数字来修复此问题:
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]
相比于完全使用 lineDashPattern
,您可以选择保持实心描边并将path
自身作为一系列小弧线来制造期望的虚线效果。这样可以确保在从0到2π旋转时,它被均匀地分成count
个小弧线:
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
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
}
}
这将产生:
UIBezierPath
的调用更改为创建一个圆形而不是圆角矩形吗? - rmaddy