I have amended some code I pulled from https://github.com/kaandedeoglu/KDCircularProgress
I have a small UIView which represents the circle progress timer. I have referenced it and also instantiated it to KDCircularProgress
class.
I have managed to implement methods to start and reset the timer progress circular bar.
But I am having trouble restarting the circular progress bar when I pause the animation.
My code preamble:
import UIKit
class SomeTableViewController: UITableViewController {
//Circular progress vars
var currentCount = 1.0
let maxCount = 60.0
//Reference selected UIView & instantiate
@IBOutlet weak var circularProgressView: KDCircularProgress!
Start animation - 60 second animation:
if currentCount != maxCount {
currentCount += 1
circularProgressView.animateToAngle(360, duration: 60, completion: nil)
}
To stop and reset the animation:
currentCount = 0
circularProgressView.animateFromAngle(circularProgressView.angle, toAngle: 0, duration: 0.5, completion: nil)
To pause the animation:
circularProgressView.pauseAnimation()
How would I set up a method to restart the animation after the paused state?
Many thanks in advance for any clarification. It's my first animation, I have tried to resolve the matter myself, but cannot seem to find any syntax applicable to my particular case.
UPDATED SOLUTION:
Thanks to @Duncan C for putting me on the right path.
I solved my problem as follows ...
Since I initiated the counter's progress using currentCount += 1
I thought I would try to pause the counter with:
if currentCount != maxCount {
currentCount -= 1
circularProgressView.animateToAngle(360, duration: 60, completion: nil)
}
which I thought would have a 'net' effect on the counter (netting off counter +=1
and counter -=1
) to effectively stop the counter. In theory this should being the counter's progress to zero, but it continued to count down.
So I reverted back to circularProgressView.pauseAnimation()
to pause the circular counter animation.
To restart the animation after being paused, I had to amend the duration to represent the updated duration - ie the time at which the animation was paused.
I used a bit of a trick here and included a NSTimer - which I happened to have in my code anyway.
To restart the animation at the time of pause:
if currentCount != maxCount {
currentCount += 1
circularProgressView.animateToAngle(360, duration: NSTimeInterval(swiftCounter), completion: nil)
}
I couldn't figure out how to update my duration for the animated circular bar, but did know how to update time passed using an NSTimer - timer with the same duration and countdown speed. So I tagged the reference to the updated timer's value. Issue resolved ;)
My Code:
import UIKit
class SomeFunkyTableViewController: UITableViewController {
//Circular progress variables
var currentCount = 0.0
let maxCount = 60.0
@IBOutlet weak var circularProgressView: KDCircularProgress!
//Timer countdown vars
var swiftTimer = NSTimer()
var swiftCounter = 60
@IBOutlet weak var startButton: UIButton!
@IBOutlet weak var timerView: UIView!
@IBOutlet weak var timerLabel: UILabel!
@IBOutlet weak var startView: UIView!
override func viewDidLoad() {
circularProgressView.angle = 0
timerLabel.text = String(swiftCounter)
super.viewDidLoad()
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func startButton(sender: AnyObject) {
pauseBtn.alpha = 1.0
playBtn.alpha = 1.0
stopBtn.alpha = 1.0
circularProgressView.hidden = false
if currentCount != maxCount {
currentCount += 1
circularProgressView.animateToAngle(360, duration: 60, completion: nil)
}
startView.hidden = true
timerView.hidden = false
swiftTimer = NSTimer.scheduledTimerWithTimeInterval(1, target:self, selector: #selector(SomeFunkyTableViewController.updateCounter), userInfo: nil, repeats: true)
}
@IBOutlet weak var pauseBtn: UIButton!
@IBAction func pauseButton(sender: AnyObject) {
circularProgressView.pauseAnimation()
swiftTimer.invalidate()
pauseBtn.alpha = 0.5
playBtn.alpha = 1.0
stopBtn.alpha = 1.0
}
@IBOutlet weak var playBtn: UIButton!
@IBAction func playButton(sender: AnyObject) {
if currentCount != maxCount {
currentCount += 1
circularProgressView.animateToAngle(360, duration: NSTimeInterval(swiftCounter), completion: nil)
}
if !swiftTimer.valid {
swiftTimer = NSTimer.scheduledTimerWithTimeInterval(1, target:self, selector: #selector(SomeFunkyTableViewController.updateCounter), userInfo: nil, repeats: true)
}
if swiftCounter == 0 {
swiftTimer.invalidate()
}
pauseBtn.alpha = 1.0
playBtn.alpha = 0.5
stopBtn.alpha = 1.0
}
@IBOutlet weak var stopBtn: UIButton!
@IBAction func stopButton(sender: AnyObject) {
currentCount = 0
circularProgressView.animateFromAngle(circularProgressView.angle, toAngle: 0, duration: 0.5, completion: nil)
circularProgressView.hidden = true
timerView.hidden = true
startView.hidden = false
swiftTimer.invalidate()
swiftCounter = 60
timerLabel.text = String(swiftCounter)
pauseBtn.alpha = 1.0
playBtn.alpha = 1.0
stopBtn.alpha = 0.5
}
func updateCounter() {
swiftCounter -= 1
timerLabel.text = String(swiftCounter)
if swiftCounter == 0 {
swiftTimer.invalidate()
}
}
}
Side Note : I have two overlapping views - StartView and TimerView. One is hidden on view load, hence the hide/unhide references. And I dim buttons on press - play/pause/stop.
Pausing and resuming an animation takes special code. You might not be able to do it without modifying the library you are using.
The trick is to set the speed on the animation on the parent layer that's hosting the animation to 0 and record the time offset of the animation.
Here are a couple of methods (written in Objective-C) from one of my projects that pause and resume an animation:
- (void) pauseLayer: (CALayer *) theLayer
{
CFTimeInterval mediaTime = CACurrentMediaTime();
CFTimeInterval pausedTime = [theLayer convertTime: mediaTime fromLayer: nil];
theLayer.speed = 0.0;
theLayer.timeOffset = pausedTime;
}
//-----------------------------------------------------------------------------
- (void) removePauseForLayer: (CALayer *) theLayer;
{
theLayer.speed = 1.0;
theLayer.timeOffset = 0.0;
theLayer.beginTime = 0.0;
}
//-----------------------------------------------------------------------------
- (void) resumeLayer: (CALayer *) theLayer;
{
CFTimeInterval pausedTime = [theLayer timeOffset];
[self removePauseForLayer: theLayer];
CFTimeInterval mediaTime = CACurrentMediaTime();
CFTimeInterval timeSincePause =
[theLayer convertTime: mediaTime fromLayer: nil] - pausedTime;
theLayer.beginTime = timeSincePause;
}
Note that starting in iOS 10, there is a newer, better way to pause and resume UIView
animations: UIViewPropertyAnimator
.
I have a sample project (written in Swift) on Github that demonstrates this new UIViewPropertyAnimator
class. Here's the link: UIViewPropertyAnimator-test
Below is an extract from the README from that project:
A UIViewPropertyAnimator
allows you to easily create UIView-based animations that can be paused, reversed, and scrubbed back and forth.
A UIViewPropertyAnimator
object takes a block of animations, very much like the older animate(withDuration:animations:)
family of UIView
class methods. However, a UIViewPropertyAnimator
can be used to run mulitiple animation blocks.
There is built-in support for scrubbing an animation by setting the fractionComplete
property on the animator. There is NOT an automatic mechanism to observe the animation progress, however.
You can reverse a UIViewPropertyAnimator
animation by setting its isReversed
property, but there are some quirks. If you change the isReversed
property of a running animator from false to true, the animate reverses, but you can't set the isReversed
property from true to false while the animation is running and have it switch direction from reverse to forward "live". You have to first pause the animation, switch the isReversed
flag, and then restart the animation. (To use an automotive analogy, you can switch from forward to reverse while moving, but you have to come to a comlete stop before you can switch from reverse back into drive.)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.