使用核心动画层动画视图

时间:2011-01-25 01:02:23

标签: objective-c cocoa macos core-animation core-graphics

我有一个NSWindow,其中包含NSView并启用了“想要核心动画层”。然后视图包含许多NSImageView,这些// AppDelegate NSRect origin = ...; NSTimeInterval d = 0.0; for (id view in views) { [view performSelector:@selector(animateFrom:) withObject:origin afterDelay:d]; d += 0.05f; } // NSImageView+Animations - (void)animateFrom:(NSRect)origin { NSRect original = self.frame; [self setFrame:origin]; [NSAnimationContext beginGrouping]; [[NSAnimationContext currentContext] setDuration:0.20f]; [[self animator] setFrame:original]; [NSAnimationContext endGrouping]; } 最初被动画到位置。当我运行动画时,它非常缓慢并且掉落了大部分帧。但是,如果我禁用“想要核心动画层”,动画效果很好。我将需要核心动画层,但无法弄清楚如何让它充分发挥作用。

我可以采取任何措施来解决性能问题吗?

以下是代码:

{{1}}

2 个答案:

答案 0 :(得分:10)

NSTimer可能会扼杀你的表现。 Core Animation对通过CAMediaTiming协议控制动画的时间安排提供了丰富的支持,您应该在应用中利用它。不要使用动画代理和NSAnimationContext,而是直接尝试使用Core Animation。如果为每个图像创建CABasicAnimation并设置其beginTime,则会延迟动画的开始。此外,为了使延迟按照您想要的方式工作,您必须将每个动画包装在CAAnimationGroup中,并将duration设置为整个动画的总时间。

使用frame属性也可能导致放缓。我真的很想在这样的情况下利用transform上的CALayer属性进行“开放”动画。您可以在IB(或代码中)的最终位置布置图像,在窗口可见之前,将其变换修改为动画的起始位置。然后,您只需将所有转换重置为CATransform3DIdentity以使接口进入正常状态。

我在我的< plug type =“无耻”> 即将推出的核心动画书< / plug> 中有一个例子,它与你的非常相似试图做。它同时动画30 NSImageView秒,没有丢帧。我为您修改了示例并将其放在github上。这些是代码中最相关的部分,其中包含无关的UI内容:

将图层转换为开始位置

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
  // ... SNIP ... //
  //Start with all of the images at the origin
  [CATransaction begin];
  [CATransaction setDisableActions:YES];
  for (CALayer *imageLayer in [[[self imageContainer] layer] sublayers]) {
    CGPoint layerPosition = [layer position];
    CATransform3D originTransform = CATransform3DMakeTranslation(20.f - layerPosition.x, -layerPosition.y, 0.f);
    [imageLayer setTransform:originTransform];
  }
  [CATransaction commit];
}

将变换设置为动画

- (IBAction)runAnimation:(id)sender {
  CALayer *containerLayer = [[self imageContainer] layer];

  NSTimeInterval delay = 0.f;
  NSTimeInterval delayStep = .05f;
  NSTimeInterval singleDuration = [[self durationStepper] doubleValue];
  NSTimeInterval fullDuration = singleDuration + (delayStep * [[containerLayer sublayers] count]);

  for (CALayer *imageLayer in [containerLayer sublayers]) {
    CATransform3D currentTransform = [[imageLayer presentationLayer] transform];

    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform"];
    anim.beginTime = delay;
    anim.fromValue = [NSValue valueWithCATransform3D:currentTransform];
    anim.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
    anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    anim.fillMode = kCAFillModeBackwards;
    anim.duration = singleDuration;

    CAAnimationGroup *group = [CAAnimationGroup animation];
    group.animations = [NSArray arrayWithObject:anim];
    group.duration = fullDuration;

    [imageLayer setTransform:CATransform3DIdentity];
    [imageLayer addAnimation:group forKey:@"transform"];
    delay += delayStep;
  }
}

如果你想查看它,我还有一个video on YouTube例子。

答案 1 :(得分:1)

您是否尝试批量处理CATransaction中的所有内容?

[CATransaction begin];
for {...}
[CATransaction commit];
  

CATransaction是核心动画机制,用于将多个图层树操作批处理到渲染树的原子更新。