项目需求,需要通过类似弧形进度条展示某项数据,在简单查阅后,根据几个作者的iOS版本进行修改,完成了Mac版本。利用贝塞尔曲线,不很复杂。

1. 主要思路

  1. 绘制背景layer层,设置lineWidth,fillColor,strokeColor与lineCap
  2. 为layer添加贝塞尔曲线路径
  3. 绘制前置进度条层,除strokeColor外均与背景layer相同
  4. 根据需求,暴露设置百分比的方法,同时会根据百分比改变进度条颜色。

2. 具体实现

2.1 背景layer层绘制

背景是一个CAShapeLayer,这是常规思路,为这个layer设置各种参数,其中lineCap是指路径起点终点的样式,默认.butt,我选择了.round

1
2
3
4
5
6
7
let backgroundLayer = CAShapeLayer()

backgroundLayer.frame = CGRect.init(x: 0, y: 0, width: rect.size.width, height: rect.size.height)
backgroundLayer.lineWidth = self.lineWidth
backgroundLayer.fillColor = NSColor.clear.cgColor
backgroundLayer.strokeColor = NSColor.gray.cgColor
backgroundLayer.lineCap = .round

2.2 添加贝塞尔曲线路径

参考的iOS代码里,UIBezierPath初始化时可以使用acr的一系列参数,但不确定是UIBezierPath和NSBezierPath之间的差别还是Swift5之后的变化,不过可以使用appendArc方法。

1
2
3
4
5
func appendArc(withCenter center: NSPoint, 
radius: CGFloat,
startAngle: CGFloat,
endAngle: CGFloat,
closewise:bool)

其中,center是圆心,radius是半径,startAngle与endAngle分别是起点终点的角度, closewise为是否顺时针,也就是从开始到结束角度,选择哪一段。

圆心和半径都是根据具体需求进行设置,由于我需要的是圆弧,所以圆心设在了frame外面,半径需要减去1/2 * lineWidth。关于起始角度,开始参考了别人blog里的这张图

我需要的大概是图中标黑的那一段,所以使用的是弧度制,开始角度为 1.25 pi , 结束角度为 1.75 pi , 但得到的圆弧总是一个整圆。后来经过尝试,改成了角度制,开始角度为145度,结束角度为45度,才得到需要的圆弧。所以这个角度不应该是上图中的取法,而是逆时针与x轴正方向的夹角。
所以我的代码如下

1
2
3
4
let center = CGPoint(x: rect.size.width/2, y: -rect.size.width/2)
let bezierPath = NSBezierPath.init()
bezierPath.appendArc(withCenter: center, radius: 1.414 * rect.size.width/2 - lineWidth/2, startAngle: 145, endAngle: 45,clockwise: true)
backgroundLayer.path = bezierPath.cgPath

2.3

前置进度条层foreLayer,设置与backgroundLayer完全一样,也许次添加上述的贝塞尔曲线,唯一区别在需要设置strokeEnd的值,是描边的进度,用来体现进度条的效果,并根据不同进度显示不同strokeColor,设置颜色和strokeEnd的值的方法暴露为public

1
2
3
4
5
6
7
8
9
10
foreLayer?.lineCap = .round
foreLayer?.path = bezierPath.cgPath
foreLayer?.strokeStart = 0
foreLayer?.strokeEnd = 0.5


backgroundLayer.addSublayer(foreLayer!)

self.layer = backgroundLayer

1
2
3
4
5
6

func setProgress(_ value: CGFloat){
self.score = value / 100
foreLayer?.strokeStart = 0
self.foreLayer?.strokeEnd = self.score
}

3 实际效果

参考链接

ios 做一个完整的渐变进度条

Swift4撸一个圆形渐变进度条

原文链接 http://blog.wuqingzhe.cn/2020/11/23/Swift用贝塞尔曲线做弧形进度条(Mac版)/