I have got this code for a circular progress view, which displays the progress for how far through a timer you are e.g. You set the timer at 60 seconds and the progress bar is halfway when you reach 30 seconds. The code is show below:
import UIKit
class TimerCircularProgressView: UIView {
@IBInspectable var timeSeconds:CGFloat = CGFloat(timers.seconds[timers.timerID]) {
didSet {
setNeedsDisplay()
}
}
@IBInspectable var timeLabelString:String = "" {
didSet {
setNeedsDisplay()
}
}
private var startAngle = CGFloat(-90 * Double.pi / 180)
private var endAngle = CGFloat(270 * Double.pi / 180)
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
private func setup() {
backgroundColor = .clear
}
override func draw(_ rect: CGRect) {
// General Declarations
guard let context = UIGraphicsGetCurrentContext() else {
return
}
// Colour Declarations
let progressColour = UIColor(red: 1, green: 1, blue: 1, alpha: 1)
let progressBackgroundColour = UIColor(red: 1, green: 1, blue: 1, alpha: 0.4)
// let titleColour = UIColor(red: 1, green: 1, blue: 1, alpha: 0.8) // let titleColour = UIColor(red: 1, green: 1, blue: 1, alpha: 0.8)
// Shadow Declarations
let innerShadow = UIColor.black.withAlphaComponent(0.22)
let innerShadowOffset = CGSize(width: 3.1, height: 3.1)
let innerShadowBlurRadius = CGFloat(4)
// Background Drawing
let backgroundPath = UIBezierPath(ovalIn: CGRect(x: rect.minX, y: rect.minY, width: rect.width, height: rect.height))
backgroundColor?.setFill()
backgroundPath.fill()
// ProgressBackground Drawing
let progressPadding = CGFloat(timers.deviceWidth / 32 * 1.5) // 15
print(progressPadding)
print(timers.deviceWidth)
let progressBackgroundPath = UIBezierPath(ovalIn: CGRect(x: rect.minX + progressPadding/2, y: rect.minY + progressPadding/2, width: rect.size.width - progressPadding, height: rect.size.height - progressPadding))
progressBackgroundColour.setStroke()
progressBackgroundPath.lineWidth = timers.deviceWidth / 32 // 5, 10
progressBackgroundPath.stroke()
// Progress Drawing
let progressRect = CGRect(x: rect.minX + progressPadding/2, y: rect.minY + progressPadding/2, width: rect.size.width - progressPadding, height: rect.size.height - progressPadding)
let progressPath = UIBezierPath()
progressPath.addArc(withCenter: CGPoint(x: progressRect.midX, y: progressRect.midY), radius: progressRect.width / 2, startAngle: startAngle, endAngle: (endAngle - startAngle) * (CGFloat(timers.seconds[timers.timerID]/timers.seconds[timers.timerID]) - (timeSeconds / CGFloat(timers.seconds[timers.timerID]))) + startAngle, clockwise: true)
progressColour.setStroke()
progressPath.lineWidth = timers.deviceWidth / 32 * 0.8 // Thickness of the progress line
progressPath.lineCapStyle = CGLineCap.round
progressPath.stroke()
// Text Drawing
let textRect = CGRect(x: rect.minX, y: rect.minY, width: rect.size.width, height: rect.size.height)
let textContent = NSString(string: timeLabelString)
let textStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
textStyle.alignment = .center
let textFontAttributes = [
NSAttributedStringKey.font: UIFont(name: "Helvetica", size: rect.width / timers.timerFontSize)!, // 3, HelveticaNeue-Light
NSAttributedStringKey.foregroundColor: UIColor.black, // NSAttributedStringKey.foregroundColor: titleColor,
NSAttributedStringKey.paragraphStyle: textStyle]
let textHeight = textContent.boundingRect(with: CGSize(width: textRect.width, height: textRect.height), options: .usesLineFragmentOrigin, attributes: textFontAttributes, context: nil).height
context.saveGState()
context.clip(to: textRect)
textContent.draw(in: CGRect(x: textRect.minX, y: textRect.minY + (textRect.height - textHeight) / 2, width: textRect.width, height: textHeight), withAttributes: textFontAttributes)
context.restoreGState();
}
}
Currently, the circular progress bar updates every seconds, which means that for short time periods, the animation of the progress section moving is jumpy, and not smooth.
I have tried setting up a timer of about 0.05 second intervals, but this can give inaccurate timings, and so I have tried 0.1 and 0.2, which still appear fairly jumpy.
@objc func processSlider() {
if secondsDDecimal > 0 {
secondsDDecimal -= 0.2
}
circularProgressView.timeSeconds = CGFloat(secondsDDecimal)
}
Is there a way to animate the transition of the circular progress view second by second, so that it is smooth and not jumpy?