I have a series of 8 UIView animations that occur directly after my view is loaded. Right now, I am accomplishing this by using the animationDidStop:finished:context
delegate method, and everything works as expected. The problem is that I have a new method for each animation. Most of the code in each of these methods is repeated, with only the animation duration and the actual positioning of elements changing.
I tried to create a single method which would be called and have the context hold the parameters needed to change the UI appropriately, but it seems to be recursively calling itself well past the amount of times I call it:
-(void)animationDidStop:(NSString *)animationID finished:(BOOL)finished context:(void *)context{
NSNumber *number = (NSNumber *)context;
int animationStep = [number intValue];
int nextAnimationStep = animationStep + 1;
NSNumber *nextAnimationStepNumber = [NSNumber numberWithInt:nextAnimationStep];
NSLog(@"Animation Step: %i", animationStep);
CGRect firstFrame = CGRectMake(self.feedsScroll.frame.size.width * 2, 0.0f, self.secondFeedView.view.frame.size.width, self.secondFeedView.view.frame.size.height);
CGRect thirdFrame = CGRectMake(self.feedsScroll.frame.size.width * 2, 0.0f, self.thirdFeedView.view.frame.size.width, self.thirdFeedView.view.frame.size.height);
[UIView beginAnimations:nil context:nextAnimationStepNumber];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDelegate:self];
if (animationStep < 8)
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
NSLog(@"Beginning animations");
switch (animationStep) {
case 0:
[UIView setAnimationDuration:.3];
self.firstFeedView.view.center = CGPointMake(self.firstFeedView.view.center.x + 30, self.firstFeedView.view.center.y);
break;
case 1:
[UIView setAnimationDuration:.3];
self.firstFeedView.view.center = CGPointMake(self.firstFeedView.view.center.x - 30, self.firstFeedView.view.center.y);
break;
case 2:
[UIView setAnimationDuration:.3];
[self.secondFeedView.view setFrame:firstFrame];
break;
case 3:
[UIView setAnimationDuration:.3];
self.secondFeedView.view.center = CGPointMake(self.secondFeedView.view.center.x + 30, self.firstFeedView.view.center.y);
break;
case 4:
[UIView setAnimationDuration:.3];
self.secondFeedView.view.center = CGPointMake(self.secondFeedView.view.center.x - 30, self.firstFeedView.view.center.y);
break;
case 5:
NSLog(@"Animation step 6");
[UIView setAnimationDuration:.5];
self.firstFeedView.view.center = CGPointMake(self.firstFeedView.view.center.x - 230, self.firstFeedView.view.center.y);
self.secondFeedView.view.center = CGPointMake(self.secondFeedView.view.center.x - 230, self.firstFeedView.view.center.y);
break;
case 6:
[UIView setAnimationDuration:.5];
[self.thirdFeedView.view setFrame:thirdFrame];
break;
case 7:
[UIView setAnimationDuration:.3];
self.thirdFeedView.view.center = CGPointMake(self.thirdFeedView.view.center.x + 30, self.firstFeedView.view.center.y);
break;
case 8:
[UIView setAnimationDuration:.3];
self.thirdFeedView.view.center = CGPointMake(self.thirdFeedView.view.center.x - 30, self.thirdFeedView.view.center.y);
break;
default:
break;
}
[UIView commitAnimations];
}
I know this is probably a naive implementation. I am new to iPhone development, and am looking for some best practices to apply here. Am I going about this in the wrong way?
The contents of your block are performed on the main thread regardless of where you call [UIView animateWithDuration:animations:] . It's best to let the OS run your animations; the animation thread does not block the main thread -- only the animation block itself.
UIView. animate runs on the main thread and is asynchronous.
You don't need to use [weak self] in static function UIView. animate() You need to use weak when retain cycle is possible and animations block is not retained by self.
it queries the views objects for changed state and gets back the initial and target values and hence knows what properties to change and in what range to perform the changes. it calculates the intermediate frames, based on the duration and initial/target values, and fires the animation.
If you're willing to step up to iOS 4.0, the new blocks-based animation approach can make this animation chaining trivial. For example:
[UIView animateWithDuration:1.0 animations:^{ view.position = CGPointMake(0.0f, 0.0f); } completion:^(BOOL finished){
[UIView animateWithDuration:0.2 animations:^{ view.alpha = 0.0; } completion:^(BOOL finished){
[view removeFromSuperview]; }];
}]
will cause view
to animate to (0, 0) over a duration of 1 second, fade out for 0.2 seconds, then be removed from its superview. These animations will be sequential.
The first block in the +animateWithDuration:animations:completion:
class method contains the property changes to animate at once, and the second is the action to be performed on completion of the animation. Because this callback can contain another animation of this sort, you can nest them to create arbitrary chains of animations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With