How to check that UIImageView has completed its animation - iphone

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

Related

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

Difference between [UIView beginAnimations:context:] and [UIView animateWithDuration:animations:]

It appears to me these two class methods are not interchangeable. I have a subview of UIView with the following code in the touchesBegan method:
if (!highlightView) {
UIImageView *tempImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Highlight"]];
self.highlightView = tempImageView;
[tempImageView release];
[self addSubview:highlightView];
}
highlightView.alpha = 0.0;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
highlightView.alpha = 1.0;
[UIView commitAnimations];
When I touch the Button, the highlight fades in, like you would expect. When I touch up immediately (before the animation is finished), my touchesEnded gets called. This is the behavior I want.
But now, I've become a big fan of blocks and try to use them wherever possible. So I replaced the UIView animation code with this:
[UIView animateWithDuration:0.2 animations:^{
highlightView.alpha = 1.0;
}];
Results: the highlight still fades in as expected, but if I touch up before the animation is finished, my touchesEnded does not get called. If I touch up after the animation is finished, my touchesEnded does get called. What's going on here?
The new animation blocks in iOS 4 by default disable user interaction. You can pass in an option to allow views to respond to touches during animation using bit flags in conjunction with the animateWithDuration:delay:options:animations:completion method of UIView as such:
UIViewAnimationOptions options = UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction;
[UIView animateWithDuration:0.2 delay:0.0 options:options animations:^
{
    highlightView.alpha = 1.0;
} completion:nil];
Documentation
One more thing is that Appple doesn't recommend to use [UIView beginAnimations:context:], you can find it in beginAnimations docs
Use of this method is discouraged in iOS 4.0 and later. You should use
the block-based animation methods to specify your animations instead.
Probably Apple can mark old methods as deprecated in the future releases and won't support them, so using block-based methods is really more preferable way for performing animation.

Animating UILabel Fade In/Out

I am going to end up with an array of RSS feeds, and would like a label or some such to display them at the bottom of the view. I would like to animate through each feed in the array.
This is what i have so far to animate, which, works for the fade, but only animates the last item of the array.
feed = [[UILabel alloc] initWithFrame:CGRectMake(0,380,320,43)];
[self.view addSubview:feed];
feed.alpha=1;
NSArray *feeds = [NSArray arrayWithObjects:[NSString stringWithFormat:#"1234567"],[NSString stringWithFormat:#"qwerty"],[NSString stringWithFormat:#"asdfgh"],nil];
for (NSString* f in feeds){
feed.text=f;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationDuration:2.0f];
feed.alpha=0;
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
[UIView commitAnimations];
}
Im sure its simple.
Thanks
First off you should really consider a better naming convention. Calling a UILabel a feed isn't very helpful for the future when you have to come back and look at your code. I would name it feedLabel. Then when you iterate through your list of feeds, you can just for (NSString *feed in feeds) and it will make more sense. And so will feedLabel.text = feed;.
Anyhow, the issue I see with your code is that your are repeatedly setting the alpha to zero in your loop, but you never set it back to one. In other words, you're not making a change to the alpha value. It stays the same in every iteration.
So maybe you could clarify what you're trying to do. If you want to fade the text between changes in the text, you'll need a different animation and methodology. Instead of a loop, chain your animations such that when your didStopSelector, you set the text and start the next one. Something like:
- (void)performAnimation;
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationDuration:2.0f];
feed.alpha=0;
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:)];
[UIView commitAnimations];
}
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
feed.alpha = 1.0;
NSString *nextFeed = [self getNextFeed]; // Need to implement getNextFeed
if (nextFeed)
{
// Only continue if there is a next feed.
[feed setText:nextFeed];
[self performAnimation];
}
}
i tried your code, it fades out on first feed, but it doesn't enter the animationDidStop event. thats why it cant call performAnimation again. is there any set for animation (delegate or protocol etc..)

Wait before execute istruction

I wan't to perform an animation before quitting a view. The problem is that if I write this code:
[self animationMethod];
[self removeFromSuperview];
the animation is not presented because the removeFromSuperview instruction is immediatly executed, i suppose.
There's a way to specify thath the removeFromSuperview method must be executed after a a specified time? thanks.
Does animationMethod use a [UIView beginAnimations: context:] section? If that's the case, you should use the animation delegate. Specifically:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(removeFromSuperview)];
//Your animation stuff
[UIView commitAnimations];
Otherwise, if you're doing something else that doesn't have a callback, you can call the method after a delay using:
[self performSelector:#selector(removeFromSuperview) withObject:nil afterDelay:0.25f];
where 0.25f is the delay you want to use. I chose 0.25 because that is the default animation length for animation blocks (as shown above).

iPhone Wait For Animation Ending

In an iPhone application, I try to catch animation endings using setAnimationDidStopSelector. I try to suspend code execution until animation ends. I have tried this; set a global BOOL variable, set it to TRUE before commiting animation and after commiting animations waited using a while loop. In the setAnimationDidStopSelector, set the BOOL variable to FALSE and hope while loop to break. But unluckily this did not work, the code did not even fall into setAnimationDidStopSelector (I check that with some trace outputs). EDIT: If that BOOL variable handling is not added, code runs into the handler method.
The code where animation takes place is below:
self.AnimationEnded=FALSE;
[UIView beginAnimations:NULL context:NULL];
[UIView setAnimationDuration:2];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
// do sth.
[UIView commitAnimations];
while(![self AnimationEnded]);
Also this is the code of handler:
- (void)animationDidStop:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context {
printf("abc\n"); fflush(stdout);
self.AnimationEnded=true;
}
What do you suggest?
In iOS 4, you can set a completion block instead of using an animation delegate and handlers. This is a simpler way of taking action when your animation has ended. I recommend using it if you aren't supporting pre-iOS 4 devices.
Your example changes to:
self.animationEnded = NO;
[UIView animateWithDuration:2
animations:^{ /* Do something here */ }
completion:^(BOOL finished){
printf("abc\n");
fflush(stdout);
self.animationEnded = YES;
}];
See +UIView animateWithDuration:animations:completion: at the iOS developer site for more.
You have to call setAnimationDelegate:to designate the object that you want the selector called upon when the animation stops. Assuming that the method that sets your flag to FALSE is in the same class as the one where you are creating the animation this will be self. For details see the UIView class reference.
Try this:
__block BOOL done = NO;
[UIView animateWithDuration:0.3 animations:^{
// do something
} completion:^(BOOL finished) {
done = YES;
}];
// wait for animation to finish
while (done == NO)
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
// animation is finished, ok to proceed
The animation will not start until this loop finishes. This loop will not finish until the animation starts.
while(![self AnimationEnded]);
Whatever you want to do after the animation needs to go in the animationDidStop method.