Search code examples
ioscore-animationcalayer

Combining multiple CAAnimations in a CALayer hierarchy


I've got this rather simple piece of example code in which I have a simple hierarchy consisting of three layers;

view layer
  |- base layer
    |- green layer

Now I want to move the base layer and at the same time adjust the color of the green layer, so I've added a slider to control the animations.

The code looks like this:

@implementation ViewController

- (void)loadView
{
    [super loadView];

    baseLayer = [CALayer layer];
    [baseLayer setFrame:[[self view] frame]];
    [baseLayer setBackgroundColor:[[[UIColor redColor] colorWithAlphaComponent:0.5] CGColor]];

    [[[self view] layer] addSublayer:baseLayer];


    greenLayer = [CALayer layer];

    [greenLayer setBounds:[baseLayer bounds]];
    [greenLayer setBackgroundColor:[[UIColor greenColor] CGColor]];

    [baseLayer addSublayer:greenLayer];


    UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(0, CGRectGetHeight([[self view] bounds]) - 44.0f, CGRectGetWidth([[self view] bounds]), 44.0f)];

    [slider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];

    [[self view] addSubview:slider];


    CABasicAnimation *changeColor = [CABasicAnimation animationWithKeyPath:@"backgroundColor"];

    changeColor.fromValue = (id)[UIColor greenColor].CGColor;
    changeColor.toValue   = (id)[UIColor blueColor].CGColor;
    changeColor.duration  = 1.0; // For convenience

    [greenLayer addAnimation:changeColor forKey:@"Change color"];

    greenLayer.speed = 0.0; // Pause the animation


    CABasicAnimation *changePosition = [CABasicAnimation animationWithKeyPath:@"position"];

    changePosition.fromValue = [NSValue valueWithCGPoint:CGPointMake(CGRectGetWidth([[self view] bounds]) / 2, CGRectGetHeight([[self view] bounds]) / 2)];
    changePosition.toValue = [NSValue valueWithCGPoint:CGPointMake(CGRectGetWidth([[self view] bounds]), CGRectGetHeight([[self view] bounds]) / 2)];
    changePosition.duration = 1.0;

    [baseLayer addAnimation:changePosition forKey:@"Change position"];

    baseLayer.speed = 0.0;        
}


- (void)sliderValueChanged:(UISlider *)slider
{
    [baseLayer setTimeOffset:[slider value]];
    [greenLayer setTimeOffset:[slider value]];
}

My question: Do I need to change the timeOffset for each layer individually (which obviously works), or am I missing something here and can I do with a more intelligent solution?

(Of course this is a simple example, but my actual hierarchy can be somewhat more complex and having an arbitrary number of layers theoretically)


Solution

  • It should work when you remove the speed = 0 from the sub layers, in this case the greenLayer.

    The speed property works relative to parent layers so you can pause all animations by adjusting the speed on the parent layer. Speed on sublayers will work relatively to the parent layer speed.