I was wondering if it is possible to know when the animation ends in a UIProgressView
Because during the animation, the progress value is already set to 1, even if it's half-way on your screen (during test)
I've noticed that using a bigger value than 1 in
TimerBar.setProgress( 0< Float < 1, animated : true) slow the animation. Bigger is the Float (bigger than one) , slower is the animation.
I would like to trigger an event when the animation ends and when the bar is full.
Thanks for your help !
PS : I know that using a NSTime can be an alternative, but I would like to try this way !
EDIT : I have noticed that the value (normally between 0 and 1) is also the time when you animate the bar
TimerBar.setProgress(10, animated : true)
The bar will take ten seconds to fill !
I've finally couples it with NSTimer.
But the other problem is the bar update now.
The bar won't care if you simply choose NO in the animation parameter while it's already performing another animation
For example :
TimerBar.setProgress(0.5, animated : false)
TimerBar.setProgress(1, animated : true)
Here the first line will be simply ignored. Any solution/ ?
Related
I have a problem with animation as I want the same animation with different end points, to be called upon finishing the previous animation and to be executed smoothly without slight stop.
Let me elaborate with a sample code and comments.
Func animate()
{
Start animation(completionHandler: {
If condition is true
Repeat the animation and check after it finishes
}
}
but the problem with this code is that, between finishing the first animation and starting another one, there will be a split second stop which is not smooth movement. For example, I have a view on zero point to move with animation to point A (x:100,y:100), and then it will receive point B (x:500, y:900), after it reaches point A it will stop a split second then move to point B. Since the points are Dynamic, I cannot know if there is a new point or not, and if I did i will not know the coordinates beforehand, so I need to keep the logic dynamic and keeps the animation smooth between points.
I tried many logics and results were not the thing I wanted. problems I faced toward a smooth queued animation are:
I tried UIView.animate in the following:
a. I tried setting an animation duration let's say 2 sec, then after it finishes, it calls animation again within completion hander/closure/block, but it will result in a less than second stop between the two animations.
b. I tried to start 2 animations, the second is delayed with the exact duration go the first animation, but results also brief stop between 2 animations.
2.I tried animation with keyframes, but since I don't know all animations in advance, this won't work.
Can you help please with my approach toward a smooth dynamic animation?
Your own pseudocode answers your question. Just test whatever your condition, and if you need to animate again, work out the new start and end points and animate again:
func animate(start:Int, end:Int) {
UIView.animate(withDuration: 5, animations: {
// animate here based on new start and end
}, completion: { _ in
var weShouldDoItAgain = false
// figure out if we should do it again
// if so, change weShouldDoItAgain to true
if weShouldDoItAgain {
var start = start // and now change it to new value
var end = end // and now change it to new value
self.animate(start:start, end:end)
}
})
}
Just change all the values and types to suit your use case.
I have a progress bar that animates from 0-1.0 continuously. I set it to 0 if the user pauses the app. The problem is if they resume quickly the progress bar doesn't go to 1.0 like it should.
I know (well am pretty sure) it's an issue with a doubling of the animation.
I have the progress bar going from 0 - 1 in 15 seconds
I pause
I set the progress bar to 0 and remove all animations
I resume right away
The progress no longer fills the bar on subsequent animations
If I wait > 15s to resume there is no issue.
Here is the code that animates my progress bar.
self.progressBar.layer.removeAllAnimations()
self.progressBar.progress = 0.0
self.progressBar.layoutIfNeeded()
self.progressBar.layer.removeAllAnimations()
self.progressBar.progress = 1.0
UIView.animate(withDuration: time) {
self.progressBar.layoutIfNeeded()
}
I go from 0 - 1.0 progress continuously and I was having issues with the completion block not going to 0 in time. (That's why it resets before it animates)
If the user pauses it:
self.progressBar.progress = 0.0
self.progressBar.layoutIfNeeded()
progressBar.layer.removeAllAnimations()
Then when I go to resume the progress bar doesn't get to 1.0 progress. It continuously increases the amount each time the func is run until after about 5 cycles.
While researching this issue I came across a SO post about using CATransaction to reset the progress bar to 0 upon completion but that caused the issue with the second, fourth, etc cycles not animating because of the speed I call it.
This issue presents itself when you try to set progress to both 0 and 1 at the same time. However, I'm not doing that here as far as I can tell. It works 100% except in this pause/resume scenario.
I am 99% sure its a doubling of progress animations but I'm not sure how that's possible when I am removing the animations before animating it.
Note: Using progressBar.setProgress doesn't change anything.
Thanks in advance
To remove all animations from progressView you can use this approach:
for (CALayer *layer in self.progressView.layer.sublayers) {
[layer removeAllAnimations];
}
I have made a CAAnimation (CAAnimationGroup to be precise) that scale and fade (opacity) from 0 -> 1 and then back 0 -> 1. The animation also repeats forever
since I have set animationGroup.repeatCount = .greatestFiniteMagnitude. This animation is applied to a UILabel and makes the label appear and disappear with a nice animation over and over.
I now want to change the text between each repetition of the animation (after it disappears but before it appears again). What is the correct way of doing this?
I managed to get this working by removing the animationGroup.repeatCount = .greatestFiniteMagnitude line and manually restarting the animation in the animation delegate method animationDidStop(_:finished:). I also change the text of the label in the delegate method before restarting the animation. I'm not sure if this is the best solution though.
So I'm making a simple trivia game and I have a timerView that shrinks as time passes. When the user selects an answer, it needs to stop shrinking immediately - it must be very responsive. I give the user 10 seconds per question. Originally I would animate 10 times (with a duration of 1.0f), calling the next "segment" of animation in the completion block of the previous animation. In the completion block I would check to see if the user has tapped an answer, and if so I don't continue the chain. That solution works fine except that it's not very responsive because it's on a per second basis-- user taps an answer at the start of the second segment and the bar has a noticeable continuation.
My solution to THAT problem was to instead have 1000 animation calls with a duration of 0.01f. After doing that, the responsiveness was on point - the view stops animating as soon as I tap an answer -- the issue though, is that it's not actually 10 seconds, it takes more like 20.
So question number 1: what's the smallest time interval animateWithDuration can actually process properly?
Question number 2: is there a better way to accomplish what I'm trying to do accomplish?
ill answer question two: yes there definitely is a better way, have a look at CADisplayLink
use it to shrink your view a little bit each frame, and end the display link when you need to
the most responsive way is: the user taps an answer, you response in the touch callback, remove animations. you can remove animations by CALayer's removeAllAnimations method
Another way to do it is to set the view to shrinking using a single animation with linear timing, and then set the speed of the view's layer to 0 to pause the animation. When you set the speed on the layer to 0 the animation pauses instantly.
This works because under the covers, UIView animation actually creates and installs CAAnimation objects on the view's layers. It's possible to pause and continue an in-flight UIView animation just like you can a CAAnimation.
I have a project called KeyframeViewAnimations (link) on github that allows you to pause, continue, or "scrub" UIView and CAAnimations back and forth with a slider. You could use that technique. The tricky bit will be figuring out how far along the animation is.
I'm developing an iOS application and I have a simple question.
If you start an animation for an image (like rotating it) for an unlimited time, and then after a few seconds set the alpha to zero to hide it [[self image]setAlpha:0];. Is the animation still working in the background or not? Do you always have to set [layer removeAllAnimations];? I'm asking this because I don't wan't to slow down the cpu.
Thanks!
You really want to use removeAllAnimations, not just setting the alpha to zero. If you use a timer or display link to monitor the presentationLayer (which indicates the current properties of the view) of the animated object, you'll see that the animation is still in progress, even if the alpha is zero.