I make a animation and make it runs it forever. And now I want to stop it after clicking a button. Then animation is rotating a image of a button from 0 to 360 degree.
I'd like to stop the animation but make the animation to finish the current cycle. For example, if the button is rotated at 200 degree, and I click the stop button, I want that the animation still runs to reach 360 degree and then stop.
The animation code is like below:
CABasicAnimation *anim2 = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
anim2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
anim2.fromValue = [NSNumber numberWithFloat:0];
anim2.toValue = [NSNumber numberWithFloat:-((360*M_PI)/180)];
anim2.repeatCount = HUGE_VALF;
anim2.duration = 10;
[self.imgBtn.layer addAnimation:anim2 forKey:#"transform"];
Thanks!
While you can get the animation from the layer using animationForKey:, you cannot modify the animation that way. As the documentation explains it:
Discussion
Attempting to modify any properties of the returned object will result in undefined behavior.
What you instead have to do
You have to remove the infinite animation and add another animation that makes the final end animation.
Use the presentation layer to determine the current rotation of your layer.
Remove the infinite animation
Add a new animation from the value you got from the presentation layer to the end state.
How to get the value from the presentation layer.
During animation your model doesn't change (when using Core Animation). Instead what you see on screen is the layers presentation layer. You can get then read the current value from the presentation layer just as if it was any other layer. In your case you could get the rotation using [myLayer valueForKey:#"transform.rotation"];
Alternately, you can create a single animation with a completion method that triggers the animation again, in an infinite loop.
Have the completion routine check a flag before submitting a repeat.
If the flag is false, don't trigger the animation again.
Then have your button action simply set the repeat flag to false. The current animation will run to completion, and then it won't be repeated.
Related
Is there a way to stop touch interaction when animation sequence is running. Animation sequence is load from ccbi file.
CCBAnimationManager* animationManager = self.userObject;
[animationManager runAnimationsForSequenceNamed:#"Blink"];
This depends on what interaction do you want to stop.
If it is a CCLayer, then set layer.touchEnabled = NO; and it will stop receiving touches. If it is your custom UI component, then you have to manually remove the touch delegate from it and add it when the animation ends.
Don't forget that you can set animationManager.delegate = self to get a callback when the animation finishes, so you can enable the touches again.
I've created a CCLayer by using Cocosbuilder. There are two timeline animations called "MyAnim1" and "MyAnim2". None of them are auto-run. MyAnim1 is chained to MyAnim2. I'm using CCBAnimationManager to run the first animation. And it works and the second animation is chained to animation 1 as I expected. But here comes a problem. The first animation goback to its initial status when the second animation start. Is this a bug? Is there a way to keep my first animation status to the end status when the second animation starts?
Sometimes i want to run gif image with animate once or twice,,and stop it,, is there possible to do that?
The animation is controlled by the Animate property of the TGIFImage control. Set it to True to animate, and set it to False to stop the animation.
There is also the AnimateLoop property. If that is True then the animation loops endlessly. Otherwise it runs once and then stops. If you want to run the animation once then set AnimateLoop to False and then set Animate to True.
Finally you have the OnLoop event. That fires each time a looped animation loops back to the start. So, if you want to show an animation twice or more then you need to set AnimateLoop to True and then count the loops in an OnLoop handler.
In my Mac OS X app, I'm trying to animate an NSView using a CAAnimation applied to the layer-backed view's layer using this code:
I create a CAAnimation:
myAnimation = [CABasicAnimation animationWithKeyPath:#"opacity"];
myAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
myAnimation.fromValue = [NSNumber numberWithFloat:1.0];
myAnimation.toValue = [NSNumber numberWithFloat:0.0];
myAnimation.duration = 3;
myAnimation.repeatCount = 1;
myAnimation.autoreverses = NO;
then I add it to the layer of my "myContentView" NSView:
[self.myContentView.layer removeAllAnimations];
[self.myContentView.layer addAnimation:myAnimation forKey:#"opacity"];
self.myContentView.layer.opacity = 0; //Set final value of opacity to this value
This actually works fine, except that every time I run the animation (triggered by a mouse click), I start by making the NSView's parent window visible and set it's alphaValue to 1, the myContentView shows for a fraction of a second at the last opacity value it was displaying when I called the above code and it hit removeAllAnimations.
It is like if the presentationLayer stays in cache and is redisplayed before the animation kicks in.
If I let the animation completely finish (by holding the mouse button down longer until it completely fades out), then the next time around, all is fine. It is only when it gets interrupted mid-way by removeAllAnimations that it seems to stick around.
I tried setting the opacity to 0 before every call to make the window visible, but that fails too. I have no idea why the layer is not set to an opacity of 0 even when I interrupt the animation.
Any suggestions? What am I not doing right?
Just to be clear, I'm not adding layers myself, just setting the NSView to be layer-backed.
My CAAnimation never calls anything on my controller if I set it as a delegate either... which is weird too. I must be doing something wrong for sure.
What is being drawn in the NSView is done programmatically in it's drawRect: method, using a bezier shape.
I found a working workaround. If I remove my view from the window's contentView just before displaying the said Window, and add it back just after, then, the ghost of the previous animation" seems to get flushed somehow and does not appear.
i am setting up a simple UISlider to animate it's progress:
[UIView animateWithDuration:songLength
delay:0.0
options:UIViewAnimationOptionRepeat|
UIViewAnimationOptionAllowUserInteraction|
UIViewAnimationOptionBeginFromCurrentState
animations:^{
[UIView setAnimationDuration:10.0];
[myUISlider setValue:10.0];
} completion:nil
];
[UIView commitAnimations];
when the user presses a button i want to stop the animation at it's place.
i understand i need to query the presentation layer to figure out the value, however, the presentation layer is of type CALayer and not UISlider. hence, it has layer properties, like it's x/y position on the screen, but not the value of the slider itself.
it makes sense that by design the presentation layer can access all the current animated data of a layer, but i'm not sure how to work that out in code.
any ideas?
i figured out one way of resolving this matter, in case you are dealing with the same issue.
by design there is no apparent way to query an animated thumb of a UISlider. animation querying works well for a layer, so one way is to create your own background and animated a layer that is the thumb.
the way i worked around this is the use of NSTimer class. once i want the progress bar to start animating i set an NSTimer for 0.1s interval and call a function to update the thumb location. the animation before/after the thumb (as it progresses the left part is blue and what's remained is still white) is taken care of for you automatically.
here is the code:
updateTimer = [NSTimer scheduledTimerWithTimeInterval:.01 target:self selector:#selector(updateCurrentTime) userInfo:p repeats:YES];
so every .01 of a second this method is called and it redraws the thumb, thus creating the animation. no need for an animation block.
this works well and i am happy with the results. i am concerned with performance and will measure how resource intensive this implementation is. it maybe a good idea to go with the first option i've mentioned above.