当前位置: > > > Swift - 三层环状进度条组件开发(仿Apple Watch上运动记录圆圈)

Swift - 三层环状进度条组件开发(仿Apple Watch上运动记录圆圈)

Apple Watch发布的时候,上面的有个类型仪表盘一样的圆形刻度盘让人印象深刻。它使用红绿蓝三色圆圈分别表示用户的活动,锻炼,站立情况。让人一眼就能了解自己当天的运动状况。

下面,我们使用Swift语言仿造一个类似的组件,暂时取名叫彩虹进度条(RainbowProgressView)。

1,彩虹进度条开发
(1)同开发其它的自定义组件一样,我们还是通过继承 UIView 来实现。
(2)整个组件由三个圆弧组成,在 drawRect() 方法中绘制添加。
(3)组件提供内、中、外三个圆圈的半径、颜色、进度属性,以及圆圈宽度属性让用户设置。
(4)组件类和属性使用IB标识,让其在StoryBoard中也能自由设置属性,并实时渲染效果。

效果图如下:
            

组件代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import Foundation
import UIKit
 
@IBDesignable
class RainbowProgressView: UIView {
    //进度条颜色(内圈、中间、外圈)
    @IBInspectable var firstColor: UIColor = UIColor(
        red: (37.0/255.0), green: (252.0/255), blue: (244.0/255.0), alpha: 1.0)
    @IBInspectable var secondColor: UIColor = UIColor(
        red: (171.0/255.0), green: (250.0/255), blue: (81.0/255.0), alpha: 1.0)
    @IBInspectable var thirdColor: UIColor = UIColor(
        red: (238.0/255.0), green: (32.0/255), blue: (53.0/255.0), alpha: 1.0)
     
    //进度条半径(内圈、中间、外圈)
    @IBInspectable var innerCircleRadius:CGFloat = 20
    @IBInspectable var middleCircleRadius:CGFloat = 45
    @IBInspectable var outerCircleRadius:CGFloat = 70
     
    //进度0~1(内圈、中间、外圈)
    @IBInspectable var firstPercent:CGFloat = 0.75
    @IBInspectable var secondPercent:CGFloat = 0.75
    @IBInspectable var thirdPercent:CGFloat = 0.75
     
    //进度条宽度
    @IBInspectable var circleWeight:CGFloat = 16
     
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
         
        backgroundColor = UIColor.clearColor()
    }
     
    override init(frame: CGRect) {
        super.init(frame: frame)
         
        backgroundColor = UIColor.clearColor()
    }
     
    // 绘制
    override func drawRect(rect: CGRect) {
        // 添加三个环形进度条
        self.addCirle(innerCircleRadius, color: firstColor, percent: firstPercent)
        self.addCirle(middleCircleRadius, color: secondColor, percent: secondPercent)
        self.addCirle(outerCircleRadius, color: thirdColor, percent: thirdPercent)
    }
     
    //添加环形进度
    func addCirle(arcRadius: CGFloat, color: UIColor, percent:CGFloat) {
        let X = CGRectGetMidX(self.bounds)
        let Y = CGRectGetMidY(self.bounds)
         
        // 进度条圆弧
        let barPath = UIBezierPath(arcCenter: CGPoint(x: X, y: Y), radius: arcRadius,
            startAngle: CGFloat(-M_PI_2), endAngle: CGFloat(M_PI*1.5),
            clockwise: true).CGPath
        self.addOval(circleWeight, path: barPath, strokeStart: 0, strokeEnd: percent,
            strokeColor: color, fillColor: UIColor.clearColor(),
            shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)
    }
     
    //添加圆弧
    func addOval(lineWidth: CGFloat, path: CGPathRef, strokeStart: CGFloat,
        strokeEnd: CGFloat, strokeColor: UIColor, fillColor: UIColor,
        shadowRadius: CGFloat, shadowOpacity: Float, shadowOffsset: CGSize) {
         
        let arc = CAShapeLayer()
        arc.lineWidth = lineWidth
        arc.path = path
        arc.strokeStart = strokeStart
        arc.strokeEnd = strokeEnd
        arc.strokeColor = strokeColor.CGColor
        arc.fillColor = fillColor.CGColor
        arc.shadowColor = UIColor.blackColor().CGColor
        arc.shadowRadius = shadowRadius
        arc.shadowOpacity = shadowOpacity
        arc.shadowOffset = shadowOffsset
        layer.addSublayer(arc)
    }
}

测试代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import UIKit
 
class ViewController: UIViewController {
 
    override func viewDidLoad() {
        super.viewDidLoad()
         
        let rainbow1 = RainbowProgressView(frame: CGRectMake(5,20,160,160))
        self.view.addSubview(rainbow1)
         
        let rainbow2 = RainbowProgressView(frame: CGRectMake(175,20,140,140))
        rainbow2.circleWeight = 18
        rainbow2.innerCircleRadius = 20
        rainbow2.middleCircleRadius = 40
        rainbow2.outerCircleRadius = 60
        rainbow2.firstPercent = 0.5
        rainbow2.secondPercent = 0.65
        rainbow2.thirdPercent = 0.75
        self.view.addSubview(rainbow2)
    }
 
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

2,组件功能改进之一:圆弧两端增加圆头
为了让圆弧没有那么生硬,我们在圆弧的两端分别添加两个圆形,这样会更圆润些。同时终点上的圆形增加了个阴影,这样效果会更好些。
            
改进后的组件代码(高亮处为修改的地方):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import Foundation
import UIKit
 
@IBDesignable
class RainbowProgressViewEx: UIView {
    //进度条颜色(内圈、中间、外圈)
    @IBInspectable var firstColor: UIColor = UIColor(
        red: (37.0/255.0), green: (252.0/255), blue: (244.0/255.0), alpha: 1.0)
    @IBInspectable var secondColor: UIColor = UIColor(
        red: (171.0/255.0), green: (250.0/255), blue: (81.0/255.0), alpha: 1.0)
    @IBInspectable var thirdColor: UIColor = UIColor(
        red: (238.0/255.0), green: (32.0/255), blue: (53.0/255.0), alpha: 1.0)
     
    //进度条半径(内圈、中间、外圈)
    @IBInspectable var innerCircleRadius:CGFloat = 20
    @IBInspectable var middleCircleRadius:CGFloat = 45
    @IBInspectable var outerCircleRadius:CGFloat = 70
     
    //进度0~1(内圈、中间、外圈)
    @IBInspectable var firstPercent:CGFloat = 0.75
    @IBInspectable var secondPercent:CGFloat = 0.75
    @IBInspectable var thirdPercent:CGFloat = 0.75
     
    //进度条宽度
    @IBInspectable var circleWeight:CGFloat = 16
     
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
         
        backgroundColor = UIColor.clearColor()
    }
     
    override init(frame: CGRect) {
        super.init(frame: frame)
         
        backgroundColor = UIColor.clearColor()
    }
     
    // 绘制
    override func drawRect(rect: CGRect) {
        // 添加三个环形进度条
        self.addCirle(innerCircleRadius, color: firstColor, percent: firstPercent)
        self.addCirle(middleCircleRadius, color: secondColor, percent: secondPercent)
        self.addCirle(outerCircleRadius, color: thirdColor, percent: thirdPercent)
    }
     
    //添加环形进度
    func addCirle(arcRadius: CGFloat, color: UIColor, percent:CGFloat) {
        let X = CGRectGetMidX(self.bounds)
        let Y = CGRectGetMidY(self.bounds)
         
        // 进度条圆弧
        let barPath = UIBezierPath(arcCenter: CGPoint(x: X, y: Y), radius: arcRadius,
            startAngle: CGFloat(-M_PI_2), endAngle: CGFloat(M_PI*1.5),
            clockwise: true).CGPath
        self.addOval(circleWeight, path: barPath, strokeStart: 0, strokeEnd: percent,
            strokeColor: color, fillColor: UIColor.clearColor(),
            shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)
         
        // 进度条起点圆头
        let startPath = UIBezierPath(ovalInRect: CGRectMake(X-circleWeight/2,
            Y-arcRadius-circleWeight/2, circleWeight, circleWeight)).CGPath
        self.addOval(0.0, path: startPath, strokeStart: 0, strokeEnd: 1.0,
            strokeColor: color, fillColor: color,
            shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)
         
        // 进度条终点圆头
        let endDotPoint = calcCircleCoordinateWithCenter(CGPoint(x: X, y: Y),
            radius: arcRadius, angle: -percent*360+90)
        let endDotPath = UIBezierPath(ovalInRect: CGRectMake(endDotPoint.x-circleWeight/2,
            endDotPoint.y-circleWeight/2, circleWeight, circleWeight)).CGPath
        self.addOval(0.0, path: endDotPath, strokeStart: 0, strokeEnd: 1.0,
            strokeColor: color, fillColor: color,
            shadowRadius: 5.0, shadowOpacity: 0.5, shadowOffsset: CGSizeZero)
    }
     
    //计算圆弧上点的坐标
    func calcCircleCoordinateWithCenter(center:CGPoint, radius:CGFloat, angle:CGFloat)
        -> CGPoint {
        let x2 = radius*CGFloat(cosf(Float(angle)*Float(M_PI)/Float(180)));
        let y2 = radius*CGFloat(sinf(Float(angle)*Float(M_PI)/Float(180)));
        return CGPointMake(center.x+x2, center.y-y2);
    }
     
    //添加圆弧
    func addOval(lineWidth: CGFloat, path: CGPathRef, strokeStart: CGFloat,
        strokeEnd: CGFloat, strokeColor: UIColor, fillColor: UIColor,
        shadowRadius: CGFloat, shadowOpacity: Float, shadowOffsset: CGSize) {
         
        let arc = CAShapeLayer()
        arc.lineWidth = lineWidth
        arc.path = path
        arc.strokeStart = strokeStart
        arc.strokeEnd = strokeEnd
        arc.strokeColor = strokeColor.CGColor
        arc.fillColor = fillColor.CGColor
        arc.shadowColor = UIColor.blackColor().CGColor
        arc.shadowRadius = shadowRadius
        arc.shadowOpacity = shadowOpacity
        arc.shadowOffset = shadowOffsset
        layer.addSublayer(arc)
    }
}

3,组件功能改进之二:添加进度条背景
看Apple Watch的运动状态圆盘可以发现,每个环形进度条后面还有一个相同色系的淡色进度槽,表示未完成的部分。
实现方式就是在各个进度条底部添加个透明圆环,颜色就是在其对应进度条颜色基础上增加透明度即可。
为了适应各种舞台背景,组件增加新属性 barBgAlpha,用于设置进度条底图的透明度。(黑色舞台背景建议0.3,白色舞台背景建议0.15)
            
改进后的组件代码(高亮处为修改的地方):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import Foundation
import UIKit
 
@IBDesignable
class RainbowProgressViewEx2: UIView {
    //进度条颜色(内圈、中间、外圈)
    @IBInspectable var firstColor: UIColor = UIColor(
        red: (37.0/255.0), green: (252.0/255), blue: (244.0/255.0), alpha: 1.0)
    @IBInspectable var secondColor: UIColor = UIColor(
        red: (171.0/255.0), green: (250.0/255), blue: (81.0/255.0), alpha: 1.0)
    @IBInspectable var thirdColor: UIColor = UIColor(
        red: (238.0/255.0), green: (32.0/255), blue: (53.0/255.0), alpha: 1.0)
     
    //进度条半径(内圈、中间、外圈)
    @IBInspectable var innerCircleRadius:CGFloat = 20
    @IBInspectable var middleCircleRadius:CGFloat = 45
    @IBInspectable var outerCircleRadius:CGFloat = 70
     
    //进度0~1(内圈、中间、外圈)
    @IBInspectable var firstPercent:CGFloat = 0.75
    @IBInspectable var secondPercent:CGFloat = 0.75
    @IBInspectable var thirdPercent:CGFloat = 0.75
     
    //进度条宽度
    @IBInspectable var circleWeight:CGFloat = 16
     
    //进度条背景槽透明度(黑色舞台背景建议0.3,白色舞台背景建议0.15)
    @IBInspectable var barBgAlpha:CGFloat = 0.3
     
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
         
        backgroundColor = UIColor.clearColor()
    }
     
    override init(frame: CGRect) {
        super.init(frame: frame)
         
        backgroundColor = UIColor.clearColor()
    }
     
    // 绘制
    override func drawRect(rect: CGRect) {
        // 添加三个环形进度条
        self.addCirle(innerCircleRadius, color: firstColor, percent: firstPercent)
        self.addCirle(middleCircleRadius, color: secondColor, percent: secondPercent)
        self.addCirle(outerCircleRadius, color: thirdColor, percent: thirdPercent)
    }
     
    //添加环形进度
    func addCirle(arcRadius: CGFloat, color: UIColor, percent:CGFloat) {
        let X = CGRectGetMidX(self.bounds)
        let Y = CGRectGetMidY(self.bounds)
         
        // 进度条圆弧背景
        var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
        color.getRed(&r, green: &g, blue: &b, alpha: &a)
        let barBgColor = UIColor(red: r, green: g, blue: b, alpha: barBgAlpha);
         
        let barBgPath = UIBezierPath(arcCenter: CGPoint(x: X, y: Y), radius: arcRadius,
            startAngle: CGFloat(-M_PI_2), endAngle: CGFloat(M_PI*1.5),
            clockwise: true).CGPath
        self.addOval(circleWeight, path: barBgPath, strokeStart: 0, strokeEnd: 1,
            strokeColor: barBgColor, fillColor: UIColor.clearColor(),
            shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)
         
        // 进度条圆弧
        let barPath = UIBezierPath(arcCenter: CGPoint(x: X, y: Y), radius: arcRadius,
            startAngle: CGFloat(-M_PI_2), endAngle: CGFloat(M_PI*1.5),
            clockwise: true).CGPath
        self.addOval(circleWeight, path: barPath, strokeStart: 0, strokeEnd: percent,
            strokeColor: color, fillColor: UIColor.clearColor(),
            shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)
         
        // 进度条起点圆头
        let startPath = UIBezierPath(ovalInRect: CGRectMake(X-circleWeight/2,
            Y-arcRadius-circleWeight/2, circleWeight, circleWeight)).CGPath
        self.addOval(0.0, path: startPath, strokeStart: 0, strokeEnd: 1.0,
            strokeColor: color, fillColor: color,
            shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)
         
        // 进度条终点圆头
        let endDotPoint = calcCircleCoordinateWithCenter(CGPoint(x: X, y: Y),
            radius: arcRadius, angle: -percent*360+90)
        let endDotPath = UIBezierPath(ovalInRect: CGRectMake(endDotPoint.x-circleWeight/2,
            endDotPoint.y-circleWeight/2, circleWeight, circleWeight)).CGPath
        self.addOval(0.0, path: endDotPath, strokeStart: 0, strokeEnd: 1.0,
            strokeColor: color, fillColor: color,
            shadowRadius: 5.0, shadowOpacity: 0.5, shadowOffsset: CGSizeZero)
    }
     
    //计算圆弧上点的坐标
    func calcCircleCoordinateWithCenter(center:CGPoint, radius:CGFloat, angle:CGFloat)
                -> CGPoint {
        let x2 = radius*CGFloat(cosf(Float(angle)*Float(M_PI)/Float(180)));
        let y2 = radius*CGFloat(sinf(Float(angle)*Float(M_PI)/Float(180)));
        return CGPointMake(center.x+x2, center.y-y2);
    }
     
    //添加圆弧
    func addOval(lineWidth: CGFloat, path: CGPathRef, strokeStart: CGFloat,
        strokeEnd: CGFloat, strokeColor: UIColor, fillColor: UIColor,
        shadowRadius: CGFloat, shadowOpacity: Float, shadowOffsset: CGSize) {
             
            let arc = CAShapeLayer()
            arc.lineWidth = lineWidth
            arc.path = path
            arc.strokeStart = strokeStart
            arc.strokeEnd = strokeEnd
            arc.strokeColor = strokeColor.CGColor
            arc.fillColor = fillColor.CGColor
            arc.shadowColor = UIColor.blackColor().CGColor
            arc.shadowRadius = shadowRadius
            arc.shadowOpacity = shadowOpacity
            arc.shadowOffset = shadowOffsset
            layer.addSublayer(arc)
    }
}

4,组件功能改进之三:进度条终点只有突出的部分有阴影
前面的样例中,我门是在进度条终点处添加了一个圆来实现突出的部分,所以其阴影在这个圆点周围都是存在的。
如果想要只让突出的部分周围有阴影,我门在上方覆盖一小段圆弧即可,这样就将后半部分的阴影盖住。(注意:当进度条很短的时候还需在起点处覆盖个纯色的圆点才行) 
           

改进后的组件代码(高亮处为修改的地方):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import Foundation
import UIKit
 
@IBDesignable
class RainbowProgressViewEx3: UIView {
    //进度条颜色(内圈、中间、外圈)
    @IBInspectable var firstColor: UIColor = UIColor(
        red: (37.0/255.0), green: (252.0/255), blue: (244.0/255.0), alpha: 1.0)
    @IBInspectable var secondColor: UIColor = UIColor(
        red: (171.0/255.0), green: (250.0/255), blue: (81.0/255.0), alpha: 1.0)
    @IBInspectable var thirdColor: UIColor = UIColor(
        red: (238.0/255.0), green: (32.0/255), blue: (53.0/255.0), alpha: 1.0)
     
    //进度条半径(内圈、中间、外圈)
    @IBInspectable var innerCircleRadius:CGFloat = 20
    @IBInspectable var middleCircleRadius:CGFloat = 45
    @IBInspectable var outerCircleRadius:CGFloat = 70
     
    //进度0~1(内圈、中间、外圈)
    @IBInspectable var firstPercent:CGFloat = 0.75
    @IBInspectable var secondPercent:CGFloat = 0.75
    @IBInspectable var thirdPercent:CGFloat = 0.75
     
    //进度条宽度
    @IBInspectable var circleWeight:CGFloat = 16
     
    //进度条背景槽透明度(黑色舞台背景建议0.3,白色舞台背景建议0.15)
    @IBInspectable var barBgAlpha:CGFloat = 0.3
     
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
         
        backgroundColor = UIColor.clearColor()
    }
     
    override init(frame: CGRect) {
        super.init(frame: frame)
         
        backgroundColor = UIColor.clearColor()
    }
     
    // 绘制
    override func drawRect(rect: CGRect) {
        // 添加三个环形进度条
        self.addCirle(innerCircleRadius, color: firstColor, percent: firstPercent)
        self.addCirle(middleCircleRadius, color: secondColor, percent: secondPercent)
        self.addCirle(outerCircleRadius, color: thirdColor, percent: thirdPercent)
    }
     
    //添加环形进度
    func addCirle(arcRadius: CGFloat, color: UIColor, percent:CGFloat) {
        let X = CGRectGetMidX(self.bounds)
        let Y = CGRectGetMidY(self.bounds)
         
        // 进度条圆弧背景
        var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
        color.getRed(&r, green: &g, blue: &b, alpha: &a)
        let barBgColor = UIColor(red: r, green: g, blue: b, alpha: barBgAlpha);
         
        let barBgPath = UIBezierPath(arcCenter: CGPoint(x: X, y: Y), radius: arcRadius,
            startAngle: CGFloat(-M_PI_2), endAngle: CGFloat(M_PI*1.5),
            clockwise: true).CGPath
        self.addOval(circleWeight, path: barBgPath, strokeStart: 0, strokeEnd: 1,
            strokeColor: barBgColor, fillColor: UIColor.clearColor(),
            shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)
         
        // 进度条圆弧
        let barPath = UIBezierPath(arcCenter: CGPoint(x: X, y: Y), radius: arcRadius,
            startAngle: CGFloat(-M_PI_2), endAngle: CGFloat(M_PI*1.5),
            clockwise: true).CGPath
        self.addOval(circleWeight, path: barPath, strokeStart: 0, strokeEnd: percent,
            strokeColor: color, fillColor: UIColor.clearColor(),
            shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)
         
        // 进度条起点圆头
        let startPath = UIBezierPath(ovalInRect: CGRectMake(X-circleWeight/2,
            Y-arcRadius-circleWeight/2, circleWeight, circleWeight)).CGPath
        self.addOval(0.0, path: startPath, strokeStart: 0, strokeEnd: 1.0,
            strokeColor: color, fillColor: color,
            shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)
         
        // 进度条终点圆头
        let endDotPoint = calcCircleCoordinateWithCenter(CGPoint(x: X, y: Y),
            radius: arcRadius, angle: -percent*360+90)
        let endDotPath = UIBezierPath(ovalInRect: CGRectMake(endDotPoint.x-circleWeight/2,
            endDotPoint.y-circleWeight/2, circleWeight, circleWeight)).CGPath
        self.addOval(0.0, path: endDotPath, strokeStart: 0, strokeEnd: 1.0,
            strokeColor: color, fillColor: color,
            shadowRadius: 5.0, shadowOpacity: 0.5, shadowOffsset: CGSizeZero)
         
        // 进度条遮罩1(圆弧)
        let barMaskPath = UIBezierPath(arcCenter: CGPoint(x: X, y: Y), radius: arcRadius,
            startAngle: CGFloat(-M_PI_2), endAngle: CGFloat(M_PI*1.5),
            clockwise: true).CGPath
        self.addOval(circleWeight, path: barMaskPath,
            strokeStart: percent/6, strokeEnd: percent,
            strokeColor: color, fillColor: UIColor.clearColor(),
            shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)
        // 进度条遮罩2(圆)
        if percent < 0.5{
            self.addOval(0.0, path: startPath, strokeStart: 0, strokeEnd: 1.0,
                strokeColor: color, fillColor: color,
                shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)
        }
    }
     
    //计算圆弧上点的坐标
    func calcCircleCoordinateWithCenter(center:CGPoint, radius:CGFloat, angle:CGFloat)
        -> CGPoint {
            let x2 = radius*CGFloat(cosf(Float(angle)*Float(M_PI)/Float(180)));
            let y2 = radius*CGFloat(sinf(Float(angle)*Float(M_PI)/Float(180)));
            return CGPointMake(center.x+x2, center.y-y2);
    }
     
    //添加圆弧
    func addOval(lineWidth: CGFloat, path: CGPathRef, strokeStart: CGFloat,
        strokeEnd: CGFloat, strokeColor: UIColor, fillColor: UIColor,
        shadowRadius: CGFloat, shadowOpacity: Float, shadowOffsset: CGSize) {
             
            let arc = CAShapeLayer()
            arc.lineWidth = lineWidth
            arc.path = path
            arc.strokeStart = strokeStart
            arc.strokeEnd = strokeEnd
            arc.strokeColor = strokeColor.CGColor
            arc.fillColor = fillColor.CGColor
            arc.shadowColor = UIColor.blackColor().CGColor
            arc.shadowRadius = shadowRadius
            arc.shadowOpacity = shadowOpacity
            arc.shadowOffset = shadowOffsset
            layer.addSublayer(arc)
    }
}
源码下载:hangge_1021.zip
评论2
  • 2楼
    2016-03-01 15:06
    1

    不需要旋转,谢谢了。

    站长回复

    好的,我下周会写篇相关的文章,你可以关注下。

  • 1楼
    2016-02-25 17:04
    1

    航哥,你好,请问下如果想做示例中的一个圆环,只是圆环从0到persent为0.5(或者其它值)的时候加动画,并且加一张图片跟着这个动画的路径从0走,该怎么做呢?我现在用UIView的animation动画改变arc.strokeEnd可以实现圆环的行走动画,但是UIImageView的动画加上去很麻烦也无法跟圆环的头同步走。

    站长回复

    图片移动的时候需要旋转吗,如果只要移动的话使用沿曲线轨迹的动画即可。下周看下有没有时间写个样例,来不及的话要下下周了。