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];
Related
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
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
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..)
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.
I tried to add a animation to viewDidLoad and viewDidAppear, but it doesn't work:
- (void)viewDidAppear:(BOOL)animated{
[UIView beginAnimations:#"transition" context:NULL];
[UIView setAnimationTransition:110 forView:self.view cache:YES];
[UIView commitAnimations];
}
Why?
I had the same problem and I think I found the solution on this SO question.
When viewDidAppear gets called you still don't see anything on the screen (despite the name), but you are about to. You can then use a performSelector:withDelay or an NSTimer to launch your animation. The delay can just be 0.1 and your animation will play just when the screen appears.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(#"View did appear!");
[self performSelector:#selector(animationCode) withObject:nil afterDelay:0.1f];
}
- (void)animationCode {
// you animation code
}
You are not telling the view which state it should animate to so it won't do anything. You need to place code between beginAnimations:context: and commitAnimations that changes the appearance of the view (e.g. by removing one subview and adding another).
You're not using beginAnimations: and commitAnimations correctly. You're supposed to put something in between them that normally wouldn't be animated: e.g. with self.view.alpha = 0.5 you get a fading effect. They have no effect on anything that isn't between them.
By the time viewDidAppear: is called, your view, well... has appeared. It's too late to animate anything. What you actually want to do is something like this:
- (void)showMyViewWithAnimation {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationTransition:110 forView:childView cache:YES];
[parentView addSubview:childView];
[UIView commitAnimations];
}
In the example above, childView is what in your example is called self.view.
Please write out the name of the transition; no one knows what 110 is by looking at it. It's bad style. </pedantry>