Objective c 使用核心动画层设置视图动画

Objective c 使用核心动画层设置视图动画,objective-c,cocoa,macos,core-animation,core-graphics,Objective C,Cocoa,Macos,Core Animation,Core Graphics,我有一个NSWindow包含一个启用了“想要核心动画层”的NSView。然后,该视图包含许多使用的NSImageView,这些视图最初设置为动画。当我运行动画时,它非常缓慢,并且会丢失大部分帧。但是,如果我禁用“想要核心动画层”,动画效果会非常好。我需要核心动画层,但不知道如何让它充分发挥作用 我能做些什么来解决性能问题吗? 代码如下: // AppDelegate NSRect origin = ...; NSTimeInterval d = 0.0; for (id view in view

我有一个
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];
}

您是否尝试在CATTransaction中批量处理所有内容

[CATransaction begin];
for {...}
[CATransaction commit];
CATTransaction是将多层树操作批处理为渲染树的原子更新的核心动画机制


NSTimer
可能正在扼杀您的性能。Core Animation通过
CAMediaTiming
协议对控制动画计时提供了丰富的支持,您应该在应用程序中充分利用这一点。不要使用animator代理和
NSAnimationContext
,而是直接尝试使用核心动画。如果为每个图像创建
cabasicanitation
,并设置其
beginTime
,则会延迟动画的开始。此外,为了获得所需的延迟,必须将每个动画包装在
CAAnimationGroup
中,并将其
持续时间设置为整个动画的总时间

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

在我即将出版的《核心动画》一书中,我举了一个例子,这个例子与您正在尝试的非常相似。它可以同时设置30个
NSImageView
s的动画,而不会删除任何帧。我为你修改了这个例子,并把它放在电脑上。以下是去掉无关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;
  }
}