Reputation: 1202
I need to display information about the current fey frame image that is being displayed via a CAKeyframeAnimation. So when the image at "values" index 0 is displayed show information in some NSTextFields about that image and when it animates to index 1 show information about that image. Is it possible to do this?
CAKeyframeAnimation *theAnimation=[CAKeyframeAnimation animationWithKeyPath:@"contents"];
theAnimation.values = myView.productImages;
theAnimation.duration = 5.0;
theAnimation.repeatCount = HUGE_VALF;
theAnimation.calculationMode = kCAAnimationDiscrete;
theAnimation.fillMode = kCAFillModeRemoved;
[myView.exampleCALayer addAnimation:theAnimation forKey:@"contents"];
[myView.exampleCALayer setNeedsDisplay];
Upvotes: 0
Views: 208
Reputation: 31
Wow, that's a great job!!! I'll use it…
Just one note, I'm on Xcode 5 and I noticed that only the first animation "slideShowAnimation" is fired.
I could fix it just by adding these two lines:
[slideShowAnimation setBeginTime:0];
[counterAnimation setBeginTime:0];
Thanks for sharing. - nIc
Upvotes: 0
Reputation: 24476
Typically you can observe a property like position, for example, pretty easily using a timer or a display link while an animation is running, however, since it's the contents property you are trying to monitor, things are little more tricky. I would suggest that you animate your own custom property. You can then animate it in a group along with your existing contents animation and get updates whenever your custom property changes.
The steps go something like this:
Override these methods:
- (id)initWithLayer:(id)layer
+ (BOOL)needsDisplayForKey:(NSString*)key
- (void)drawInContext:(CGContextRef)ctx
Create the property you want to override in the header
Here is what your layer might look like in its implementation:
@implementation MLImageLayer
- (id)initWithLayer:(id)layer
{
if(self = [super initWithLayer:layer]) {
if([layer isKindOfClass:[MLImageLayer class]]) {
MLImageLayer *other = (MLImageLayer*)layer;
[self setCounter:[other counter]];
}
}
return self;
}
+ (BOOL)needsDisplayForKey:(NSString*)key
{
if ([key isEqualToString:@"counter"]) {
return YES;
} else {
return [super needsDisplayForKey:key];
}
}
- (void)drawInContext:(CGContextRef)ctx
{
DLog(@"Counter is: %d", _counter);
}
@end
Then, to actually animate the property, do this:
CAKeyframeAnimation *counterAnimation = [CAKeyframeAnimation
animationWithKeyPath:@"counter"];
[counterAnimation setDelegate:self];
NSArray *values = @[@(0), @(1), @(2), @(3), @(4), @(5)];
[counterAnimation setValues:values];
[counterAnimation setDuration:5.0];
[counterAnimation setRepeatCount:HUGE_VALF];
[counterAnimation setCalculationMode:kCAAnimationDiscrete];
Now, back in your derived layer's -drawInContext: method, you can monitor the counter value and then respond accordingly.
This can be a bit tricky, though, since you're animating two properties at the same time. You'll have to use a group to get it to work right:
- (void)viewDidLoad
{
[super viewDidLoad];
_animationLayer = [MLImageLayer layer];
[_animationLayer setBounds:CGRectMake(0.0f, 0.0f, 400.0f, 320.0f)];
[_animationLayer setPosition:[[self view] center]];
UIImage *image = [UIImage imageNamed:@"Countryside.jpg"];
[_animationLayer setContents:(__bridge id)[image CGImage]];
[[[self view] layer] addSublayer:_animationLayer];
CAKeyframeAnimation *slideShowAnimation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
[slideShowAnimation setValues:@[(id)[[UIImage imageNamed:@"Countryside.jpg"] CGImage],
(id)[[UIImage imageNamed:@"Countryside-1.jpg"] CGImage],
(id)[[UIImage imageNamed:@"Countryside-2.jpg"] CGImage],
(id)[[UIImage imageNamed:@"Countryside-3.jpg"] CGImage],
(id)[[UIImage imageNamed:@"Countryside-4.jpg"] CGImage],
(id)[[UIImage imageNamed:@"Countryside-5.jpg"] CGImage]]];
[slideShowAnimation setDuration:5.0];
[slideShowAnimation setDelegate:self];
[slideShowAnimation setRepeatCount:HUGE_VALF];
[slideShowAnimation setCalculationMode:kCAAnimationDiscrete];
CAKeyframeAnimation *counterAnimation = [CAKeyframeAnimation animationWithKeyPath:@"counter"];
[counterAnimation setDelegate:self];
NSArray *values = @[@(0), @(1), @(2), @(3), @(4), @(5)];
[counterAnimation setValues:values];
[counterAnimation setDuration:5.0];
[counterAnimation setRepeatCount:HUGE_VALF];
[counterAnimation setCalculationMode:kCAAnimationDiscrete];
CAAnimationGroup *group = [CAAnimationGroup animation];
[group setDuration:5.0];
[group setRepeatCount:HUGE_VALF];
[group setAnimations:@[slideShowAnimation, counterAnimation]];
[_animationLayer addAnimation:group forKey:nil];
}
I posted a project up on github. It's written for iOS, but you should be able to adapt the Core Animation specific code in an OSX app.
Upvotes: 1