CABasicAnimation 执行不可靠

Posted

技术标签:

【中文标题】CABasicAnimation 执行不可靠【英文标题】:Unreliable execution from CABasicAnimation 【发布时间】:2014-08-29 21:34:02 【问题描述】:

我正在尝试在 CALayer 上实现自定义属性的动画。我已经将该属性设置为动态的,并且它主要工作。在我的应用程序中,我可能有十几个或更多该层的实例,所有这些实例都应该同时进行动画处理。但是,有时当动画被触发时,一些图层不执行动画。他们简单地直接跳转到最终值。

在尝试调试问题时,看起来当动画开始时,出现问题的图层会在其模型图层上重新绘制动画属性的最终值。其余层仅使用动画属性的瞬态值在其表示层上重绘。通常是最后一层有问题,但有时是随机层。

它是如此零星,我不确定下一步该往哪里看。

这里是触发动画的sn-p代码:

@dynamic aspectModeFraction;

- (id<CAAction>)actionForKey:(NSString *)key

    if ([key isEqualToString:@"aspectModeFraction"])
    
        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:key];
        animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
        animation.fromValue = @([[self presentationLayer] aspectModeFraction]);
        animation.duration = 2.0f;
        animation.delegate = self;
        return animation;
    
    return [super actionForKey:key];


+ (BOOL)needsDisplayForKey:(NSString *)key 

    if ([@"fullRect"           isEqualToString:key])  return YES; 
    if ([@"localRect"          isEqualToString:key])  return YES; 
    if ([@"screens"            isEqualToString:key])  return YES; 
    if ([@"aspectModeFraction" isEqualToString:key])  return YES; 

    return [super needsDisplayForKey:key];

【问题讨论】:

您对动画的要求如何?根据我的经验,使用键值编码总是有效的。所以如果你说例如myLayer.aspectModeFraction = whatever,试着改用 [myLayer setValue:whatever forKey:@"aspectModeFraction"] 看看是否有区别。 【参考方案1】:

看起来您拥有大部分零件。自定义属性动画中有很多小部分,this talk 可能仍然有帮助,看起来您可能已经完成了主要工作。

我首先怀疑调用代码。我会确保你没有抑制动画,或者修改主线程之外的任何 UIKit 片段。

值得注意的是,使用@dynamic 复制图层属性的技巧可能不受官方支持。 (这是“似乎有效”的事情之一,而不是来自我认识的任何文档;当我与一些 Apple 工程师谈论它时,他们从未听说过这样做。)如果你仅在 10.9+ 上遇到问题,您可以尝试将您对 @dynamic 的使用替换为您在 initWithLayer: 中复制的标准属性。

【讨论】:

动画自定义属性是官方的;有 Apple sample code 专门展示了如何做到这一点。事实上,整个动画系统都是专门设计成可以通过这种方式进行扩展的。 我知道您可以为自定义属性设置动画。事实上,我所说的@动态属性自动复制没有记录在案,并且可能没有得到真正的支持。如果您查看链接的代码,它们会在initWithLayer: 中实现复制,以及使用@dynamic。 (参见 CustomAnimatableProperty/BulbLayer.m)您没有表明您有一个 initWithLayer: 方法来处理这个问题。【参考方案2】:

感谢您的建议。我最终找到了问题所在。我已经优化了绘图代码,只在这个参数改变时才做一些计算。当参数更新时,我将计算标记为脏,以便在下一个绘制循环期间重新计算它们。脏标志是通过参数上的自定义设置器设置的。当我切换到@dynamic(这似乎是 CAAnimations 所必需的?)时,自定义设置器必须消失,所以我通过让对象自己执行 KVO 来更新脏标志。事实证明,observeValueForKeyPath:... 在动画期间没有被调用。它对最终值进行了一次更新,但没有中间值。

无论如何,每次都放弃优化并进行完整计算可以解决问题。 KVO 在动画值上没有按预期工作似乎是罪魁祸首。

【讨论】:

以上是关于CABasicAnimation 执行不可靠的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 CABasicAnimation 从一个点移动到另一个点?

在 CABasicAnimation 期间 UIButton 未显示选定状态

CABasicAnimation的delegate的坑

Core Animation2-CABasicAnimation

CABasicAnimation 链接不起作用

如何正确设置 CABasicAnimation(开始)时间?