How exactly to subclass CALayer and use a custom property?

I am trying to create a subclass of CALayer with a custom index property that I can both animate and change directly in order to display a different picture based on the index.

In the header, I declared:

@property NSUInteger index;

In the implementation, I overrode needDisplayForKey :

+ (BOOL)needsDisplayForKey:(NSString *)key
{
    if ([key isEqualToString:@"index"])
        return YES;
    else
        return [super needsDisplayForKey:key];
}

Now, in the display method, I want to display a picture based on the index. However, during an animation, the value of self.index never changes, so I have to query the value of the presentation layer, contrary to the example on Providing CALayer Content by Subclassing:

- (void)display
{
    NSUInteger presentationIndex = [(CustomLayer *)[self presentationLayer] index];
    self.contents = (id)[[images objectAtIndex:presentationIndex] CGImage];
}

The problem is, if I do that, I cannot set the index value directly outside of an animation, because it will only change the model layer, and the display method explicitly queries the presentation layer.

If I add an initialization method that copies the value of index , it works:

- (id)initWithLayer:(id)layer
{
    self = [super initWithLayer:layer];
    if (self) {
        if ([layer isKindOfClass:[CustomLayer class]])
            self.index = [(CustomLayer *)layer index];
    }
    return self;
}

However, after or before an animation, there is always a 1 image glitch because the presentation or the model value don't match (depending if I set index to the destination value or not).

  • Surprisingly, it seems like the drawInContext: method always has the right value for [self index] , but it is not the method I want to use since I just set the content property with an image.
  • I get different behaviors depending on the way I implement the index property. If I use @dynamic index (which works, even though the documentation doesn't say that custom property getters/setters would be dynamically implemented), display is called every time the value of index is changed. If I use @synthesize or implement a setter, display is not called, so I would need to change content in the setter too.
  • Should I use an instance variable? Should I use the dynamic implementation? Or should I use setValue:forKey: instead?
  • As you can see, I am a bit confused about how to get the result I want, and how to correctly implement a subclass of CALayer with a custom property. Any help, and explanations, would be appreciated!


    There is an excellent tutorial on the web that explains how to create a custom CALayer subclass with animatable properties. I haven't had occasion to try it yet, but I bookmarked it. Here is the link:

    Animating Pie Slices Using a Custom CALayer

    It looks like the main tricks are:

    Use @dynamic, not @synthesize for the animatable properties of your custom CALayer.

    Override actionForKey:, initWithLayer:, and needsDisplayForKey:, and perhaps drawInContext:

    链接地址: http://www.djcxy.com/p/74168.html

    上一篇: 核心动画的不可预知行为(CABasicAnimation)

    下一篇: 如何继承CALayer并使用自定义属性?