views:

1484

answers:

2

I have two animations that I'm trying to perform on a UILabel on the iPhone with OS 3.1.2. The first rocks the UILabel back and forth:

CAKeyframeAnimation *rock;
rock = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
[rock setBeginTime:0.0f];
[rock setDuration:5.0];
[rock setRepeatCount:10000];

NSMutableArray *values = [NSMutableArray array];
MovingMath *math = [[MovingMath alloc] init];

// Center start position
[values addObject:[math DegreesToNumber:0]];

// Turn right
[values addObject:[math DegreesToNumber:-10]];

// Turn left
[values addObject:[math DegreesToNumber:10]];

// Re-center
[values addObject:[math DegreesToNumber:0]];

// Set the values for the animation
[rock setValues:values];

[math release];

The second zooms the UILabel so that it becomes larger:

NSValue *value = nil;
CABasicAnimation *animation = nil;
CATransform3D transform;
animation = [CABasicAnimation animationWithKeyPath:@"transform"];
transform = CATransform3DMakeScale(3.5f, 3.5f, 1.0f);
value = [NSValue valueWithCATransform3D:transform];
[animation setToValue:value];
transform = CATransform3DMakeScale(1.0f, 1.0f, 1.0f);
value = [NSValue valueWithCATransform3D:transform];
[animation setFromValue:value];
[animation setAutoreverses:YES];
[animation setDuration:30.0f];
[animation setRepeatCount:10000];
[animation setBeginTime:0.0f];

Adding either one of these animations directly to the UILabel's layer works as expected.

However, if I try to group the animations together, the first "rocking" animation does not function:

CAAnimationGroup *theGroup = [CAAnimationGroup animation];

theGroup.duration = 5.0;
theGroup.repeatCount = 10000;
theGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
theGroup.animations = [NSArray arrayWithObjects:[self rockAnimation], [self zoomAnimation], nil]; // you can add more

// Add the animation group to the layer
[[self layer] addAnimation:theGroup forKey:@"zoomAndRotate"];

The order of adding the animations to the group does not matter. Instead of zooming, in the manner above, I tried changing the bounds, but that was unsuccessful as well. Any insight would be greatly appreciated. Thank you.

A: 

I believe CAAnimationGroup is not what you want. From the documentation for CAAnimationGroup:

CAAnimationGroup allows multiple animations to be grouped and run concurrently. The grouped animations run in the time space specified by the CAAnimationGroup instance.

It sounds like you do not want your animations to run concurrently, rather sequentially. There may be easier ways to do this, but I've found relying on the animationDidStop:finished: method works well. To do this, create your first animation, and set it's delegate to an object which will implement the animationDidStop:finished: method, and add the animation as normal (without using CAAnimationGroup). In the method:

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
    // Create the second animation and add it
}
CJ
I do want these to happen at the same time. The problem is that when using the group, rockAnimation does not run. Only zoomAnimation runs.
Christian
The duration of the grouped animations are not scaled to the duration of their CAAnimationGroup. Instead, the animations are clipped to the duration of the animation group. You may want to try making all your animations run in 5 seconds (and remove repeatCounts) to see if that's the issue.
CJ
Unfortunately that didn't work either.
Christian
+1  A: 

You are attempting to simultaneously animate two changes to one property, your CALayer's transform. In the first animation, you are using a helper keypath to change the transform to produce a rotation, and in the second you are changing the transform directly to produce a scaling. The second animation is overwriting the first, because you are constructing whole transforms that are only scaled and animating between them.

It appears that you can cause both scaling and rotation of your layer to occur by using helper keypaths for both animations. If you change your code on the scaling animation to read

CABasicAnimation *animation = nil;
animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
[animation setToValue:[NSNumber numberWithDouble:3.5]];
[animation setFromValue:[NSNumber numberWithDouble:1.0]];
[animation setAutoreverses:YES];
[animation setDuration:30.0f];
[animation setRepeatCount:10000];
[animation setBeginTime:0.0f];

you should be able to have both rocking and scaling on your layer.

Brad Larson
Thank you, that worked!
Christian
I have exactly the same problem but it's not working for me on iPad 3.2, I try to access the rotation and scale property but the grouped animation stops immediately after some milliseconds and the layers snaps back!
brutella