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;
}
}