Search code examples
cocoacore-animationcocoa-bindingscalayerkey-value-observing

How to bind the scale of a CAConstraint?


I want to bind the scale of a CAConstraint so that a CALayer's width with respect to it's superlayer can indicate progress (of a QTMovie) based on a variable that I am updating in a scheduled timer method that fires every second. The width of the CALayer should be 0.0f when progress is zero and 100% the width of the superlayer when progress is complete (i.e. currentProgress == 1.0f). The way that I have created the layer with the constraint is as follows:

self.progressLayer = [[[CALayer alloc] init] autorelease];

progressLayer.name = @"progressLayer";
progressLayer.backgroundColor = [Utilities blackColour];

[progressLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinX relativeTo:@"superlayer" attribute:kCAConstraintMinX]];
[progressLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintHeight relativeTo:@"superlayer" attribute:kCAConstraintHeight]];
[progressLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidY relativeTo:@"superlayer" attribute:kCAConstraintMidY]];
CAConstraint* constraint = [CAConstraint constraintWithAttribute:kCAConstraintWidth relativeTo:@"superlayer" attribute:kCAConstraintWidth scale:0.0f offset:0.0f];
[constraint bind:@"scale" toObject:[MediaPlayer sharedMediaPlayer] withKeyPath:@"currentProgress" options:nil];
[progressLayer addConstraint:constraint];

The problem that I have is that when I update the currentProgress variable in my method that is fired every second, the CALayer doesn't update it's width at all. To start with testing my code I am just incrementing the progress value by 0.01f and I am logging the amount and it is definitely updating. However, when I update the amount based on a button click, the layer updates correctly.

Just for good measure this is how I am updating the variable in my NSTimer method within my MediaPlayer class:

- (void) checkProgress:(NSTimer*)timer {
    self.currentProgress += 0.01f;
    NSLog(@"checkProgress: %f", currentProgress);
}

And on a button press I update it like so:

self.currentProgress += 0.1f;

Why isn't the width of the layer updating based on the changes in my method but updates on the button press? Does anyone have any ideas for me to follow to try and figure this out?

Thanks!


Solution

  • It turns out that with my button click I was modifying a "brother/sister" layer (another layer added to it's superlayer) which seems to have prompted the layer to do an update of itself. By not modifying the other layer, my layer that I was constraining just didn't update. So it seems that constraining a variable of a CAConstraint won't keep the CALayer updated. Maybe this is because CAConstraint doesn't have a setter for the scale. And if it had a setter it would be able to tell the layer that it needs to be updated. So I have gone about setting the width of my layer a different way.