2

I've got a CAShapeLayer subclass which features two properties, a startPoint and an endPoint. These properties aren't directly drawn into the context but rather used to alter the path property, similar to the transform, position and bounds properties.

Here's the code of the whole layer

-(void)setStartPoint:(CGPoint)startPoint {
    if (!CGPointEqualToPoint(_startPoint, startPoint)) {
        _startPoint = startPoint;

        [self reloadPath];
    }
}

-(void)setEndPoint:(CGPoint)endPoint {
    if (!CGPointEqualToPoint(_endPoint, endPoint)) {
        _endPoint = endPoint;

        [self reloadPath];
    }
}

-(id)initWithLayer:(CRPathLayer*)layer {
    self = [super initWithLayer:layer];
    if (self && [layer isKindOfClass:[CRPathLayer class]]) {
        self.startPoint = layer.startPoint;
        self.endPoint = layer.endPoint;
    }

    return self;
}

+(BOOL)needsDisplayForKey:(NSString *)key {
    if ([key isEqualToString:NSStringFromSelector(@selector(startPoint))] || [key isEqualToString:NSStringFromSelector(@selector(endPoint))]) {
        return YES;
    }

    return [super needsDisplayForKey:key];
}

-(void)reloadPath {
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, self.startPoint.x, self.startPoint.y);
    CGPathAddLineToPoint(path, NULL, self.endPoint.x, self.endPoint.y);

    self.path = path;
    CGPathRelease(path);
}

However there's a problem. I need to animate one of the two new properties (start- or endPoint). I'm aware of the fact that I could just animate the path property directly, however this is not what I want to achieve. I'm obviously missing something in the implementation. When I try to animate it using a CABasicAnimation nothing happens at all.

Can anybody help me out here? Thanks in advance.

lbrndnr
  • 3,361
  • 2
  • 24
  • 34

1 Answers1

1

The piece you are missing is the actionForKey: method (and that while the path is animatable, it's not implicitly animatable (i.e. it won't animate just because the property changes)).

What you have to do is to supply an action (a more general term for an animation) for the path whenever the startPoint or endPoint changes (or just make the path implicitly animatable so that setting a new path causes an animation, they really do the same thing).

It could looks something like this (I typed this out in the browser so it may not compile):

- (id <CAAction>)actionForKey:(NSString *)key 
{
    if ([key isEqualToString:@"startPoint"] || [key isEqualToString:@"endPoint")]) {
        CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"path"];
        anim.fromValue = [self.presentationLayer valueFoKey:@"path"];
        return animo;
    }

    return [super valueForKey:key];
}
David Rönnqvist
  • 56,267
  • 18
  • 167
  • 205
  • Hmm, turns out that actionForKey is not even called for @"startPoint" or @"endPoint" – lbrndnr Mar 30 '14 at 13:59
  • Core Animation likes its properties `@dynamic`. Have you done that? – David Rönnqvist Mar 30 '14 at 14:33
  • Well I've tried to but then the problem arises of when I should recalculate the path. – lbrndnr Mar 30 '14 at 14:34
  • You could stick with what you've got an check for `@"path"` in `actionForKey:` – David Rönnqvist Mar 30 '14 at 14:36
  • Well the thing is that I also need to set calculate the path without an animation. What I did now is to observe start- and endPoint. If they change, it'll reload the path. The problem is that the animations still don't work. actionForKey is invoked, however only while initializing. So the presentationLayer's path is still nil. – lbrndnr Mar 30 '14 at 15:33