How to know when a Core Animation has finished? - iphone

say I have...
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
CGPoint position = myObject.center;
position.x = position.x - 10;
myObject.center = position;
[UIView commitAnimations];
Core animation happens on a separate thread is there a way to know when
an animation has finished? i.e., maybe there's some way I can hook up a
function call to know when it got finished... ?
(p.s I know I can use a timer that fires a method after say 0.5s in this
above example, but that seems pretty cheesy)
any help much appreciated!

You can set the setAnimationDidStopSelector:
http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/clm/UIView/setAnimationDidStopSelector:
(void)setAnimationDidStopSelector:(SEL)selector
Then implement a method for that selector
[UIView setAnimationDidStopSelector:#selector(finishedAnimation:finished:context:)];
- (void) finishedAnimation:(NSString *)id finished:(BOOL) finished context:(void *) context {
......
}
Hope that helps.

Related

How to check that UIImageView has completed its animation

I am new to iPhone development. I am using UIImageView to animate the images in an array. I am deciding that the animation is stopped through a property called isAnimating. But it always returns true.
I want to check that the animation is completed or there is some duration left to complete the animation.
Please let me know, how I can check it.
Make a property BOOL IsAnimating
then do this code
{
[UIView beginAnimations:#"Animation of ImageVIew Begins" context:nil];
IsAnimating =YES;
[UIView setAnimationDuration:0.4]; //you can put your time
NSLog(#" Animating");
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(AnimationComplete)];
// Your animation code here
[UIView commitAnimations];
}
- (void) AnimationComplete
{
isAnimating = NO;
}
Your BOOl variable will be YES till the animation is complete..then it will change to NO
Use a delegate based on the duration to trigger whatever method you want on the receiver.
you should be doing your animation inside animation blocks:
[UIView animateWithDuration:duration animations:^{
//animation code here
} completion:^(BOOL finished)
{
//this will be called when the animation is finished
}];
edit: this answer is wrong and probably shouldnt have been accepted, for anyone coming here looking for the right answer: this answers this question i think

Why won't this animation selector get called?

OK, I know there are tons of questions like this, but for some reason I can't figure out why the hell this callback selector doesn't get called?
Here are two methods which I added to a new view-based template.
I linked up a button to the IBAction, and a UIView to the redRect outlet.
The animation works fine, but for some reason which I can't figure out, the callback isn't called.
- (IBAction)toggleView:(id)sender {
float target;
if (redRect.alpha == 0.0) target = 1.0;
else target = 0.0;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationDidStopSelector:#selector(finished)];
redRect.alpha = target;
[UIView commitAnimations];
}
- (void)finished {
NSLog(#"Why won't this get called?");
}
Please tell me what I'm doing wrong here - This is so simple but I just can't figure it out.
You're forgetting to call [UIView setAnimationDelegate:]. Otherwise, how would it know who to call?
You're missing [UIView setAnimationDelegate:self];

Moving an object without animating it in an animation block

I'm animating a bunch of buttons so they move to the left of the screen then they should magically move to the right of the screen. I do this by calling:
[NSTimer scheduledTimerWithTimeInterval:0.20 target:self selector:#selector(moveTheButtons) userInfo:nil repeats:YES];
in viewDidLoad.
They animate quite happily to the left, but then they animate back to the right. I just want them to disappear and reappear to the right-off-screen. Because I'm new I assumed that since it was after the commitAnimations call that it wouldn't animate. I think the problem is that the animations actually 'commit' after the moveTheButtons function returns, but I can't think of an elegant (or standard) way around this.
How do I move the UIButton off screen without animating it, preferably still in the moveTheButtons function?
As you can probably infer, I'm new to animations on the iPhone, so if you see any other mistakes I'm making feel free to give me some pointers.
-(void)moveTheButtons{
NSLog(#"moveTheButtons");
[UIView beginAnimations:#"mov-ey" context:cloudA];
[UIView setAnimationDuration: .20];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
cloudA.center = CGPointMake(cloudA.center.x-pos.x,cloudA.center.y);
[UIView commitAnimations];
if(cloudA.center.x < -100){
//I don't want to animate this bit.
cloudA.center = CGPointMake(550,cloudA.center.y);
}
//NSLog(#"cloudA.center.x %f", cloudA.center.x);
}
You can temporarily turn off the implicit animations of properties within an animation block using the +[UIView setAnimationsEnabled:] method. This can be very useful in many use cases.
Do something like this:
-(void)moveTheButtons {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration: .20];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
CGPoint center = CGPointMake(cloudA.center.x - pos.x, cloudA.center.y);
if (center.x < -100) {
[UIView setAnimationsEnabled:NO];
cloudA.center = CGPointMake(550, center.y);
[UIView setAnimationsEnabled:YES];
} else {
cloudA.center = center;
}
[UIView commitAnimations];
}
As a side note; there is no need to give the animation a name, or a context, unless you actually use a delegate that responds to delegate methods. Just pass nil, and NULL as I have done in this example.
Precalculate the point , invert the order and return before animating the block.
You are unconditionally committing an animation to the engine in all cases.
-(void)moveTheButtons{
NSLog(#"moveTheButtons");
CGPoint mypoint = CGPointMake(cloudA.center.x-pos.x,cloudA.center.y);
if(cloudA.center.x < -100){
//I don't want to animate this bit.
cloudA.center = CGPointMake(550,cloudA.center.y);
return;
}
[UIView beginAnimations:#"mov-ey" context:cloudA];
[UIView setAnimationDuration: .20];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
cloudA.center = mypoint;
[UIView commitAnimations];
}
Theres a style point about using a return rather than if/else but you can form your own opinion.
Cheers

iPhone SDK - how can I tell when an animation has finished?

I am starting an animated enlargement when an image is touched, and then scaling it back down to normal size when it is released. By using setAnimationBeginsFromCurrentState:YES the zooming effect is nice and smooth if you lift your finger part way through animating.
However, what I want to do is "lock" the larger size in place if you've touched the image for long enough for the animation to complete, but let it shrink back down as normal if you release prematurely.
Is there a way to tell whether there is currently an animation running, or whether a particular animation has completed?
I figure I can probably do this with a performSelector:afterDelay: call in touchesStarted, with a delay equal to the length of the animation and cancelling it if touchesEnded comes too soon, but I can't imagine that's the best way...?
- (void)animateStuff {
[UIView beginAnimations:#"animationName" context:nil];
[UIView setAnimationDelegate:self];
[self.view doWhatever];
[UIView commitAnimations];
}
- (void)animationDidStop:(NSString *)animationID
finished:(NSNumber *)finished
context:(void *)context
{
if ([finished boolValue]) {
NSLog(#"Animation Done!");
}
}
Another possibility:
[UIView animateWithDuration:0.3 animations:^{
myView.transform = CGAffineTransformMakeRotation(M_PI);
}completion:^(BOOL finished) {
NSLog(#"Animation complete!");
}];
I think "+ (void)setAnimationDidStopSelector:(SEL)selector" should do what you want. It will call the given selector on your delegate once the animation has completed.

help! when playing a sound the animation freeze\pauses

basically whenever i play a sound the animation slowing down or pauses, what to do ???
sound size 20kb mp3.
animation size 5kb png.
code:
- (void) startAnimation {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.8];
CGPoint destination = CGPointMake(152,20);
pink.center = destination;
[UIView commitAnimations];
[soundPink play];
}
- (void) initSoundResources {
soundPink = [[APlayer alloc] initWithFile:#"pink" type:#"mp3"];
soundPink = 0.4;
}
Edit:
I've just noticed that in initSoundResources, you are alloc'ing and init'ing an APlayer object, but then assigning a float to the pointer straight afterwards. I'm pretty sure this isn't what you're intending.
Try this:
- (void) startAnimation {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.8];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(playSound)];
CGPoint destination = CGPointMake(152,20);
pink.center = destination;
[UIView commitAnimations];
}
- (void) initSoundResources {
soundPink = [[APlayer alloc] initWithFile:#"pink" type:#"mp3"];
soundPink = 0.4;
}
- (void) playSound {
//assuming initSoundResources is called at some point before this...
[soundPink play];
}
The idea here is that UIView animations are asynchronous. If the animation is set to be 0.8 seconds long, that doesn't mean the code will take 0.8 seconds to run.
What I mean is that the code straight after the UIView animations code gets called effectively instantly after the animation code. In this case the sound is going to play (probably) before the animation even starts.
I can't imagine why it would pause or freeze, but using this method should work.
In my code, I have taken the assumption that the initSoundResources method is called at some point before trying to play the sound.
If the soundPink pointer is not initialised to nil or a valid sound instance, then sending it the play message may cause a crash.