-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathACRCircleView.swift
More file actions
123 lines (102 loc) · 3.71 KB
/
ACRCircleView.swift
File metadata and controls
123 lines (102 loc) · 3.71 KB
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
//
// CircleView.swift
// License: MIT
//
// Created by Andrew Crookston <andrew@caoos.com> on 4/25/15.
//
//
import UIKit
class ACRCircleView: UIView {
// MARK: Configurable values
var strokeWidth : CGFloat = 2.0 {
didSet {
basePathLayer.lineWidth = strokeWidth
circlePathLayer.lineWidth = strokeWidth
}
}
override var tintColor : UIColor! {
didSet {
circlePathLayer.strokeColor = tintColor.CGColor
}
}
var baseColor : UIColor = UIColor(red: 240.0/255.0, green: 240.0/255.0, blue: 240.0/255.0, alpha: 1) {
didSet {
basePathLayer.strokeColor = baseColor.CGColor
}
}
var progress: CGFloat {
get {
return circlePathLayer.strokeEnd
}
set {
if (newValue > 1.0) {
circlePathLayer.strokeEnd = 1.0
} else if (newValue < 0.0) {
circlePathLayer.strokeEnd = 0.0
} else {
circlePathLayer.strokeEnd = newValue
}
}
}
// MARK: Init
private let basePathLayer = CAShapeLayer()
private let circlePathLayer = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
func startAnimating() {
var animation = CABasicAnimation(keyPath: "transform.rotation.z")
animation!.fromValue = 0.0
animation!.toValue = 2 * M_PI
// this might be too fast
animation!.duration = 1
// HUGE_VALF is defined in math.h so import it
animation!.repeatCount = Float.infinity
circlePathLayer.addAnimation(animation, forKey: "rotation")
}
func stopAnimating() {
circlePathLayer.removeAnimationForKey("rotation")
}
// MARK: Internal
private func configure() {
basePathLayer.frame = bounds
basePathLayer.lineWidth = strokeWidth
basePathLayer.fillColor = UIColor.clearColor().CGColor
basePathLayer.strokeColor = baseColor.CGColor
basePathLayer.actions = ["strokeEnd": NSNull()]
layer.addSublayer(basePathLayer)
circlePathLayer.frame = bounds
circlePathLayer.lineWidth = strokeWidth
circlePathLayer.fillColor = UIColor.clearColor().CGColor
circlePathLayer.strokeColor = tintColor.CGColor
// make optional for animated? See: http://stackoverflow.com/questions/21688363/change-cashapelayer-without-animation
circlePathLayer.actions = ["strokeEnd": NSNull()]
// rotate the layer negative 90deg to make it start at the top. 12 o'clock, default is 3 o'clock.
circlePathLayer.transform = CATransform3DMakeRotation(-CGFloat(90.0 / 180.0 * M_PI), 0.0, 0.0, 1.0)
layer.addSublayer(circlePathLayer)
progress = 0
}
private func circleFrame() -> CGRect {
// keep the circle inside the bounds
let shorter = (bounds.width > bounds.height ? bounds.height : bounds.width) - strokeWidth
var circleFrame = CGRect(x: 0, y: 0, width: shorter, height: shorter)
circleFrame.origin.x = CGRectGetMidX(circlePathLayer.bounds) - CGRectGetMidX(circleFrame)
circleFrame.origin.y = CGRectGetMidY(circlePathLayer.bounds) - CGRectGetMidY(circleFrame)
return circleFrame
}
private func circlePath() -> UIBezierPath {
return UIBezierPath(ovalInRect: circleFrame())
}
override func layoutSubviews() {
super.layoutSubviews()
basePathLayer.frame = bounds
basePathLayer.path = circlePath().CGPath
circlePathLayer.frame = bounds
circlePathLayer.path = circlePath().CGPath
}
}