Created
February 16, 2017 20:59
-
-
Save katiesmillie/c7c096b0e81003a09279c48f9e4c1a5b to your computer and use it in GitHub Desktop.
Circular Progress View (starts at the 12:00 position like App Store or Netflix downloading indicator)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Adapated from https://www.raywenderlich.com/94302/implement-circular-image-loader-animation-cashapelayer | |
// Swift 3 | |
// Init with frame size or set in storyboard and use an IBOutlet | |
// Set end stroke to 1 and animate with duration, or pass in the progress (between 0 and 1) while downloading, etc | |
class CircleProgressView: UIView { | |
let circlePathLayer = CAShapeLayer() | |
let circleRadius: CGFloat = 10.0 | |
let progressPathLayer = CAShapeLayer() | |
let progressRadius: CGFloat = 9.0 | |
let stopButtonPathLayer = CAShapeLayer() | |
let stopButtonWidth: CGFloat = 5.0 | |
var progress: CGFloat { | |
get { | |
return progressPathLayer.strokeEnd | |
} | |
set { | |
if newValue > 1 { | |
progressPathLayer.strokeEnd = 1 | |
} else if newValue < 0 { | |
progressPathLayer.strokeEnd = 0 | |
} else { | |
progressPathLayer.strokeEnd = newValue | |
} | |
} | |
} | |
override init(frame: CGRect) { | |
super.init(frame: frame) | |
configure() | |
} | |
required init(coder aDecoder: NSCoder) { | |
super.init(coder: aDecoder)! | |
configure() | |
} | |
func configure() { | |
circlePathLayer.frame = bounds | |
circlePathLayer.lineWidth = 1 | |
circlePathLayer.fillColor = UIColor.clear.cgColor | |
circlePathLayer.strokeColor = UIColor.blue.cgColor | |
circlePathLayer.strokeEnd = 1 | |
progressPathLayer.frame = bounds | |
progressPathLayer.lineWidth = 2 | |
progressPathLayer.fillColor = UIColor.clear.cgColor | |
progressPathLayer.strokeColor = UIColor.blue.cgColor | |
stopButtonPathLayer.fillColor = UIColor.blue.cgColor | |
stopButtonPathLayer.frame = bounds | |
layer.addSublayer(circlePathLayer) | |
layer.addSublayer(progressPathLayer) | |
layer.addSublayer(stopButtonPathLayer) | |
backgroundColor = UIColor.white | |
progress = 0 | |
} | |
func circleFrame() -> CGRect { | |
var circleFrame = CGRect(x: 0, y: 0, width: 2 * circleRadius, height: 2 * circleRadius) | |
circleFrame.origin.x = circlePathLayer.bounds.midX - circleFrame.midX | |
circleFrame.origin.y = circlePathLayer.bounds.midY - circleFrame.midY | |
return circleFrame | |
} | |
func progressFrame() -> CGRect { | |
var progressFrame = CGRect(x: 0, y: 0, width: 2 * progressRadius, height: 2 * progressRadius) | |
progressFrame.origin.x = progressPathLayer.bounds.midX - progressFrame.midX | |
progressFrame.origin.y = progressPathLayer.bounds.midY - progressFrame.midY | |
return progressFrame | |
} | |
func stopButtonFrame() -> CGRect { | |
var stopButtonFrame = CGRect(x: 0, y: 0, width: stopButtonWidth, height: stopButtonWidth) | |
stopButtonFrame.origin.x = stopButtonPathLayer.bounds.midX - stopButtonFrame.midX | |
stopButtonFrame.origin.y = stopButtonPathLayer.bounds.midY - stopButtonFrame.midY | |
return stopButtonFrame | |
} | |
func circlePath() -> UIBezierPath { | |
return UIBezierPath(ovalIn: circleFrame()) | |
} | |
func progressPath() -> UIBezierPath { | |
return UIBezierPath(ovalIn: progressFrame()) | |
} | |
func stopButtonPath() -> UIBezierPath { | |
return UIBezierPath(rect: stopButtonFrame()) | |
} | |
override func layoutSubviews() { | |
super.layoutSubviews() | |
progressPathLayer.frame = bounds | |
circlePathLayer.frame = bounds | |
stopButtonPathLayer.frame = bounds | |
stopButtonPathLayer.path = stopButtonPath().cgPath | |
circlePathLayer.path = circlePath().cgPath | |
progressPathLayer.path = progressPath().cgPath | |
// Rotate the layer so the stroke starts at the 12:00 position | |
let startAngle = 3 * .pi / 2 | |
progressPathLayer.transform = CATransform3DMakeRotation(startAngle, 0.0, 0.0, 1.0) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment