Repeat beginAnimations -- All Animations - iphone

I'm making a simple image rotator by fading in and out 4 different images. It works great, until the end, when I want all four animations to repeat.
I've tried the repeat count, but that will only apply to that one specific animation. How do I create an entire loop?
My code is below. Thanks in advance!
[UIView beginAnimations:nil context:nil];
[UIView setAnimationTransition:UIViewAnimationTransitionNone forView:slideshow cache:YES];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:3];
[UIView setAnimationRepeatAutoreverses:YES];
[UIView setAnimationDelay:3];
imageOne.alpha = 0;
imageTwo.alpha = 1;
[UIView setAnimationDelay:6];
imageTwo.alpha = 0;
imageThree.alpha = 1;
[UIView setAnimationDelay:9];
imageThree.alpha = 0;
imageFour.alpha = 1;
[UIView commitAnimations];

You can start by putting a name to your animations so instead of beginAnimations:nil, you'd put beginAnimations: #"Button Animations" or something like that. Also, you should set the delegate of the animation to self. This can be done by adding the following line of code into your animation block:
[UIView setAnimationDelegate: self];
Then you can put this whole entire animation block into a class method of it's own (in your view controller). Lets call it doAnimation. This is just for safe measure. the next thing you should do is implement this delegate function in your view controller:
-(void) animationDidStop: (NSString *) animationID finished:(NSNumber *)finished context:(void *)context{
if([animationID isEqualToString:#"Button Animation"]){
[self doAnimation];
}
}
So pretty much this will ensure that your animations will repeat. If this method doesn't work, let me know, I didn't test it. But I think it'll work.

Related

beginAnimation with For Statement not working

-updated code-
-(void)animateDot {
dotMotion.center = (*doodlePoints)[0];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationRepeatCount:100];
for(int i = 1; i < doodlePoints->size(); i++){
dotMotion.center = (*doodlePoints)[i];
}
[UIView commitAnimations];
}
I have a vector of points and I want this to do the animation from point to point. I am only getting from the 2nd to the last to the last working. not anything before.
Any ideas?
So i tried doing this differently. Nothing.
My application has to work 3.x so i can't use animation blocks.
Even better try the following:
-(void) nextAnimation
{
CGPoint point = [[self.animatePoints objectAtIndex:0] CGPointValue];
[self.animatePoints removeObjectAtIndex:0];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationRepeatCount:100];
dotMotion.center = point;
[UIView commitAnimations];
}
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{
if ([self.animatePoints count] > 0) {
[self nextAnimation];
}
}
-(void)animateDot {
self.animatePoints = [NSMutableArray array];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
for(int i = 1; i < doodlePoints->size(); i++){
[self.animatePoints addObject:[NSValue valueWithCGPoint:(*doodlePoints)[i]]];
}
[self nextAnimation];
}
This is a rough example of loading the individual points in an NSMutableArray property that is incrementally processed and emptied as each animation completes. You could just as easily use an internal index property to the doodlePoints array but I did it this way should you ever need to pass in a different collection of points. In my example we set the animation delegate and callback selector so we can be told about each animation completing. We then schedule the an animation to the next point and remove it from the array.
You need to exit from your for loop, and return from this method, after each line segment for each animation segment to be displayed. The UI is only updated after you return to the UI run loop.
Continue each iteration of the loop in another delayed or delegate callback method. Save the iterrator variable in an instance variable between methods.
You want something similar to this (not tested):
-(void)animateTo:(CGPoint) point {
dotMotion.center = (*doodlePoints)[0];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationRepeatCount:100];
dotMotion.center = point;
[UIView commitAnimations];
}
-(void)animateDot {
for(int i = 1; i < doodlePoints->size(); i++){
[self animateTo:(*doodlePoints)[i]];
}
}
Though you probably don't want to schedule these to run concurrently. You'd probably like to chain the animations using the animation completion callback and fire off the next one in sequence after each animation completes. Edited for formatting

animations on infinite loop

I have 5 different animations that animate then disappear one after another. Is there a way to put them on an infinite loop so animation #1 begins and ends, then anim #2 begins and ends etc..? the whole process then would repeat on an infinite loop.
I have the animations in separate blocks on delays. I'm guessing that there is a better way of doing this. this is what I have at the moment:
-(void) firstAnimation {
[UIView beginAnimations:#"Fade Out Image" context:nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationDelay:40];
[UIView setAnimationRepeatCount:30];
[UIView setAnimationRepeatAutoreverses:YES];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
theImage.alpha = 1;
theImage.alpha = 0.1;
[UIView commitAnimations];
[self secondAnimation];
}
-(void) secondAnimation {
tapImage2.hidden = NO;
[UIView beginAnimations:#"Fade Out Image" context:nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationDelay:53];
[UIView setAnimationRepeatCount:29];
[UIView setAnimationRepeatAutoreverses:YES];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
theImage2.alpha = 1;
theImage2.alpha = 0.1;
[UIView commitAnimations];
[self thirdAnimation];
}
this then goes on for 5 animations. thanks for any help.
Instead of using the delay, set the animation delegate and create an animation done method. I notice you are already setting the delegate.
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationFinished:finished:context:)];
- (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void *)context {
//Start next animation based on the animationID of the last one...
}

Repeating animations using the Stop Selector

I'm trying to repeat an animation until a certain condition is met. Something like this:
- (void) animateUpdate {
if (inUpdate) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:2.0];
[UIView setAnimationDelegate: self];
[UIView setAnimationDidStopSelector: #selector(animateUpdate)];
button.transform = CGAffineTransformMakeRotation( M_PI );
[UIView commitAnimations];
}
}
This will run the first time, but it won't repeat. The selector will just be called until the application crashes.
How should I do this?
Thanks.
Same issue. Here is some code that does the same thing
- (void)beginRotation{
[UIView beginAnimations:#"ghostRotate" context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:5.0];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
ghostImage.transform = CGAffineTransformMakeRotation(M_PI*0.5);
[UIView commitAnimations];
}
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context{
if ([finished boolValue]){
[self beginRotation];
}
}
When the first animation completes, it calls the didStop... This calls the beginAnimation method again which returns immediately to the didStop again. finished is set to 1 and it enters a stack overflow condition...
thoughts?
Core Animation works asynchronously, that is, your code does not block the thread and the animation actually starts at the next pass of the run loop. In order to repeat an animation you should restart it in your animation-did-stop selector or explicitly use CAAnimation's repeatCount, depending on your needs. Otherwise Core Animation will coalesce all your animations into one.

Triggering other animation after first ending Animation (Objective-C)

I have a simple animation which simply modify the position of a button:
[UIView beginAnimation:nil context:nil];
[UIView setAnimationsDuration:3.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
mybutton.frame = CGREctMake(20, 233, 280, 46);
[UIView commitAnimations];
I want to perform some other animations when this one is finish, how to do that?
You could look at setAnimationBeginsFromCurrentState:. All the animations are run in their own threads, so [UIView commitAnimations] is a nonblocking call. So, if you begin another animation immediately after committing the first one, after appropriately setting whether or not it begins from the current state, I think you'll get the behavior you want. To wit:
[UIView beginAnimation:nil context:nil];
// set up the first animation
[UIView commitAnimations];
[UIView beginAnimation:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:NO];
// set up the second animation
[UIView commitAnimations];
Alternately, you could provide a callback by doing something like
[UIView beginAnimation:nil context:nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)
// set up the first animation
[UIView commitAnimations];
//...
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
// set up the second animation here
}
a code segment for getting start.. setup initial (the first) animation:
- (void) aniPath:(AnimationPath *) path
{
[UIView beginAnimations:path->aniname context:path];
[UIView setAnimationDuration:path->interval];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(aniDone:finished:context:)];
// your initial animation
[UIView commitAnimations];
}
chains to another animation when the first is done:
- (void) aniDone:(NSString *) aniname finished:(BOOL) finished context:(void *) context
{
AnimationPath *path = (AnimationPath *) context;
if ([aniname isEqualToString:path->aniname]) {
[UIView beginAnimations:path->aniname context:context];
[UIView setAnimationDuration:path->interval];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(aniDone:finished:context:)];
// more animations, even recursively
[UIView commitAnimations];
}
}
Use the +[UIVIew setAnimationDelegate:] and +[UIView setAnimationDidStopSelector:] methods to configure your class to receive a message when the animation ends.
it quite easier.
you can just
- (void)animationDidContiune:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
UIView *currentObj = context;
[self callTheAnimation: currentObj];
}
you can easily loop the animation.
To end it - I would create an animationDidEnded and use it instead of animationDidContiune
once you want to stop it (like simple if in animation that chooses either to contiune or end).
HF.
AND WHAT's IMPORTANT:
use this type of animating meths:
- (void)callTheAnimation:(UIView*)itemView
{
[UIView beginAnimations:#"animation" context:itemView];
.
.
.
}
they are quite flexible - you can animate whatever here due to hierarchy of the objects.

How can I use this animation code?

I'm a newbie and I need some help.
I want to display a popup image over a given UIView, but I would like it to behave like the UIAlertView or like the Facebook Connect for iPhone modal popup window, in that it has a bouncy, rubbber-band-like animation to it.
I found some code on the net from someone who was trying to do something similar. He/she put this together, but there was no demo or instructions.
Being that I am so new, I don't have any idea as to how to incorporate this into my code.
This is the routine where I need the bouncy image to appear:
- (void) showProductDetail
{
. . .
////////////////////////////////////////////////////////////////////////
// THIS IS A STRAIGHT SCALE ANIMATION RIGHT NOW. I WANT TO REPLACE THIS
// WITH A BOUNCY RUBBER-BAND ANIMATION
_productDetail.transform = CGAffineTransformMakeScale(0.1,0.1);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
_productDetail.transform = CGAffineTransformMakeScale(1,1);
[UIView commitAnimations];
}
. . .
}
This is the code I found:
float pulsesteps[3] = { 0.2, 1/15., 1/7.5 };
- (void) pulse {
self.transform = CGAffineTransformMakeScale(0.6, 0.6);
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:pulsesteps[0]];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(pulseGrowAnimationDidStop:finished:context:)];
self.transform = CGAffineTransformMakeScale(1.1, 1.1);
[UIView commitAnimations];
}
- (void)pulseGrowAnimationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:pulsesteps[1]];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(pulseShrinkAnimationDidStop:finished:context:)];
self.transform = CGAffineTransformMakeScale(0.9, 0.9);
[UIView commitAnimations];
}
- (void)pulseShrinkAnimationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:pulsesteps[2]];
self.transform = CGAffineTransformIdentity;
[UIView commitAnimations];
}
Thanks in advance for any help that you can give me.
It's pretty simple. In your showProductDetail method, you start an animation block, then set the _productDetail.transform property, and then commit the block. This is what makes the animation happen.
The code that you found is designed to do a chain of such animations, but the property being modified is on self instead of on _productDetail. If _productDetail is an instance of a class that you created yourself, you can put the animation code inside that class.
Otherwise, just move the code inside the pulse method to the showProductDetail method, and put the two other methods below that method. Replace self.transformwith _productDetail.transformin all three methods.