views:

183

answers:

2

So I have some animation blocks to create some very simple animations on my app (eg. a wheel spinning continuously). This is the code for the animation (I have changed if from the old commitanimations style block but was getting the same problem with that).

[UIView animateWithDuration:30 delay:0.0
     options:(UIViewAnimationOptionAllowUserInteraction |
     UIViewAnimationOptionCurveLinear 
  |  UIViewAnimationOptionRepeat)
animations:^(void){
     wheel.transform = CGAffineTransformMakeRotation(M_PI*-0.5);
 }
completion:^(BOOL finished){
 if(finished){NSLog(@"^^^^^^^^wheel^^^^FINSIHED");
   ]}
}];

The problem I have is that on OS4 when the app has been dismissed to the multitasking bar and resumed the animation stops. If on resume I reset the position when the app becomes active again, like this....

wheel.transform = CGAffineTransformMakeRotation(0);

then it continues.

This isn't ideal because my animation skips when it restarts. I don't understand why this happens or why I should need to do this.

The "on finished" method gets called almost immediately as the animation starts which is odd as this animation should never finish. Also it DOES NOT get called when the app becomes active and the animation actually stops.

Anyone any ideas or suggestions? I'm been struggling with this for some time now...

+1  A: 

You should either setup a timer using NSTimer or use CADisplaylink like so: displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(animateImages:)]; and change the rotation CGAffineTransformMakeRotation(degrees) of your view in the delegate method.

Andrew Macpherson
Thanks, I could use a timer to animate the parts, I hadn't really thought about that. It seems more complicated though, do you know why my method above isn't working??
`NSTimer` or `CADisplayLink` are much better choices for long-running animations such as this. `UIView` animations are meant to be short-lived, usually as a result of user interaction.
Steve Madsen
A: 

The syntax of your code is invalid; your code will not compile as shown. A correct version would be:

    [UIView animateWithDuration:2 delay:0.0
                    options:(UIViewAnimationOptionAllowUserInteraction |
                             UIViewAnimationOptionCurveLinear 
                             |  UIViewAnimationOptionRepeat)
                 animations:^(void){
                     wheel.transform = CGAffineTransformMakeRotation(M_PI*-0.5);
                 }
                 completion:^(BOOL finished){
                     if(finished) NSLog(@"^^^^^^^^wheel^^^^FINSIHED");
                 }
     ];

The reason why the "on finished" block is called when the app resumes after suspension and you set the animation going again is that the wheel's transform is already at its final position (this is where you set it in your animations block). So, when the app resumes, you must first reset the wheel's transform (I would do this by setting it to CGAffineTransformIdentity) and then set the animation going.

A smarter approach would be to use CGAffineTransformRotate (and not CGAffineTransformMakeRotation). That way, you can set the transform based on what the transform is now, rather than setting it absolutely.

    [UIView animateWithDuration:2 delay:0.0
                    options:(UIViewAnimationOptionAllowUserInteraction |
                             UIViewAnimationOptionCurveLinear 
                             |  UIViewAnimationOptionRepeat)
                 animations:^(void){
                     wheel.transform = CGAffineTransformRotate(view.transform, (M_PI*-0.5));
                 }
                 completion:^(BOOL finished){
                     // whatever
                 }
    ];

I presume that your wheel is symmetric with respect to your chosen angle, so the user will never see the difference, and the slip you're complaining about (when you reset the transform) will be eliminated.

matt