Skip to content

Instantly share code, notes, and snippets.

@trilliwon
Created February 27, 2019 02:12
Show Gist options
  • Save trilliwon/047d30b1e3ca52ee2c7e077e02fba9df to your computer and use it in GitHub Desktop.
Save trilliwon/047d30b1e3ca52ee2c7e077e02fba9df to your computer and use it in GitHub Desktop.
class DownloadCircleProgressView: UIView {
// Interface
var progress: Float = 0.0 {
didSet {
// animate from [oldValue] to [newValue]
animateProgressLayer(from: CGFloat(oldValue), to: CGFloat(progress), duration: 0.1)
}
}
var color: UIColor = .white
// start: top center, direction: clockwise
private let angle = (start: -CGFloat.pi / 2, end: 3 * CGFloat.pi / 2)
private lazy var outerRingLayer: CAShapeLayer = {
let outerLayer = CAShapeLayer()
outerLayer.frame = bounds
return outerLayer
}()
private lazy var progressLayer: CAShapeLayer = {
let progressLayer = CAShapeLayer()
progressLayer.frame = bounds
return progressLayer
}()
private let animation = CABasicAnimation()
override func draw(_ rect: CGRect) {
let center = CGPoint(x: bounds.width / 2, y: bounds.height / 2)
outerRingLayer.removeFromSuperlayer()
outerRingLayer.path = UIBezierPath(arcCenter: center, radius: bounds.height / 2, startAngle: angle.start, endAngle: angle.end, clockwise: true).cgPath
outerRingLayer.shadowColor = UIColor.black.cgColor
outerRingLayer.shadowOffset = CGSize(width: 1.0, height: 1.0)
outerRingLayer.shadowOpacity = 0.5
outerRingLayer.strokeStart = 0.0
outerRingLayer.strokeEnd = 1.0
outerRingLayer.fillColor = UIColor.clear.cgColor
outerRingLayer.lineWidth = 2.0
outerRingLayer.strokeColor = color.cgColor
layer.addSublayer(outerRingLayer)
progressLayer.removeFromSuperlayer()
progressLayer.path = UIBezierPath(arcCenter: center, radius: bounds.height / 4, startAngle: angle.start, endAngle: angle.end, clockwise: true).cgPath
progressLayer.strokeStart = 0.0
progressLayer.strokeEnd = 0.0
progressLayer.fillColor = UIColor.clear.cgColor
progressLayer.strokeColor = color.cgColor
progressLayer.lineWidth = bounds.height / 2
layer.addSublayer(progressLayer)
}
private func animateProgressLayer(from: CGFloat, to: CGFloat, duration: CFTimeInterval) {
progressLayer.removeAnimation(forKey: "strokeEnd")
animation.keyPath = "strokeEnd"
animation.fromValue = from
animation.toValue = to
animation.duration = duration
animation.isRemovedOnCompletion = false
animation.isAdditive = true
animation.fillMode = CAMediaTimingFillMode.forwards
progressLayer.add(animation, forKey: "strokeEnd")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment