CALAyer子类中的不可动画属性

时间:2014-07-06 16:12:42

标签: objective-c ios7 core-animation

我已经定义了一个CALayer的子类,其中包含一个动画属性,如here所述。我现在想为该层添加另一个(不可动画的)属性以支持其内部簿记。

我在drawInContext:中设置了新属性的值,但我发现在下一次调用时它总是重置为0。是这样的,因为Core Animation假设这个属性也用于动画,并且它动画"动画"它在常数0处的值缺少进一步的指令?在任何情况下,如何将真正的非动画属性添加到CALayer的子类?

我找到了一个初步解决方法,它使用全局CGFloat _property代替@property (assign) CGFloat property,但更喜欢使用普通属性语法。

更新1

这就是我尝试在MyLayer.m中定义属性的方法:

@interface MyLayer()

@property (assign) CGFloat property;

@end

这就是我在drawInContext:

末尾为其分配值的方法
self.property = nonZero;

该财产是例如在drawInContext:的开头阅读,如下所示:

NSLog(@"property=%f", self.property);

更新2

也许这是导致问题(代码继承自this样本)?

- (id)actionForKey:(NSString *) aKey {
    if ([aKey isEqualToString:@"someAnimatableProperty"]) {
       CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:aKey];
       animation.fromValue = [self.presentationLayer valueForKey:aKey];
       return animation;
    }
    return [super actionForKey:aKey]; // also applies to my "property"
}

1 个答案:

答案 0 :(得分:9)

要从绘图方法中访问标准属性,在动画期间,您需要进行一些修改。

实施初始化程序

当CoreAnimation执行动画时,会创建图层的阴影副本,每个副本将在不同的帧中呈现。要创建此类副本,它会调用-initWithLayer:。 来自Apple's documentation

  

如果要实现自定义图层子类,则可以覆盖此方法并使用它将实例变量的值复制到新对象中。子类应始终调用超类实现。

因此,您需要实现-initWithLayer:并使用它在新实例上手动复制属性的值,如下所示:

- (id)initWithLayer:(id)layer
{
    if ((self = [super initWithLayer:layer])) {
        // Check if it's the right class before casting
        if ([layer isKindOfClass:[MyCustomLayer class]]) {
            // Copy the value of "myProperty" over from the other layer
            self.myProperty = ((MyCustomLayer *)layer).myProperty;
        }
    }
    return self;
}

通过模型层访问属性

副本,无论如何,在动画开始之前发生:您可以通过向NSLog添加-initWithLayer:来查看此内容。因此,就CoreAnimation而言,您的财产将始终为零。此外,它创建的副本是 readonly ,如果您尝试在self.myProperty内设置-drawInContext:,当在其中一个演示文稿副本上调用该方法时,您会得到一个例外:

*** Terminating app due to uncaught exception 'CALayerReadOnly', reason:  
    'attempting to modify read-only layer <MyLayer: 0x8e94010>' ***

您应该编写

,而不是设置self.myProperty
self.modelLayer.myProperty = 42.0f

因为modelLayer会将引用到原始MyCustomLayer实例,并且所有演示文稿副本共享相同的模型。请注意,在读取变量时也必须执行此操作,而不仅仅是在设置时。为了完整性,还应该提及属性presentationLayer,而不是返回正在显示的图层的当前(副本)。