【发布时间】:2015-12-08 22:33:06
【问题描述】:
我正在尝试使用 6 个CALayer 对象创建一个相当简单的动画,每个对象都被一个路径所掩盖。但是,在尝试为它们设置动画时,我遇到了明显的滞后峰值。 Here is a video of the animation running. 我可以通过将shouldRasterize 设置为YES 来提高性能,但是它会导致文本像素化,正如您从这张图片中看到的那样:
我可以通过将rasterizationScale 设置为屏幕比例来纠正像素化,但这会带回在没有光栅化的情况下出现的延迟峰值!
这是我的代码:
@interface splashLayer : CALayer
@end
@implementation splashLayer {
UIColor* color;
CALayer* l1, *l2, *l3, *l4, *l5, *l6;
CAShapeLayer* m1, *m2, *m3, *m4, *m5, *m6;
NSUInteger i;
}
-(instancetype) init {
if (self = [super init]) {
color = [lzyColors purpleColor];
i = 0;
m1 = [CAShapeLayer layer]; m2 = [CAShapeLayer layer]; m3 = [CAShapeLayer layer]; m4 = [CAShapeLayer layer]; m5 = [CAShapeLayer layer]; m6 = [CAShapeLayer layer];
self.shouldRasterize = YES;
self.rasterizationScale = screenScale(); // Slows down performance, but stops ugly pixelation.
CGMutablePathRef p = CGPathCreateMutable();
CGFloat const meanScreenLength = (screenHeight()+screenWidth())*0.5;
CGFloat const pythag = lzyMathsPythag(meanScreenLength, meanScreenLength);
CGFloat const halfPythag = pythag*0.5;
CGFloat const pythagHalfPythag = lzyMathsPythag(halfPythag, halfPythag);
CGPoint const center = screenCenter();
CGPoint p1 = {center.x, center.y-pythagHalfPythag};
CGPoint p2 = {center.x+pythagHalfPythag, center.y};
CGPoint p3 = {center.x, center.y+pythagHalfPythag};
CGPoint p4 = {center.x-pythagHalfPythag, center.y};
CGPathMoveToPoint(p, nil, p1.x, p1.y);
lzyCGPathAddLineToPath(p, p2);
lzyCGPathAddLineToPath(p, p3);
lzyCGPathAddLineToPath(p, p4);
CGPathCloseSubpath(p);
m1.path = p; m2.path = p; m3.path = p; m4.path = p; m5.path = p; m6.path = p;
CGPathRelease(p);
m1.position = (CGPoint){-pythag, -pythag}; m2.position = (CGPoint){-pythag, -pythag}; m3.position = (CGPoint){-pythag, -pythag};
m4.position = (CGPoint){pythag, pythag}; m5.position = (CGPoint){pythag, pythag}; m6.position = (CGPoint){pythag, pythag};
l1 = [CALayer layer];
l1.contents = (__bridge id _Nullable)(colorImage([color lightenByValue:0.6], screenSize()).CGImage);
l1.frame = (CGRect){CGPointZero, screenSize()};
l1.mask = m1;
l2 = [CALayer layer];
l2.contents = (__bridge id _Nullable)(textBG([color lightenByValue:0.3], screenSize()).CGImage);
l2.frame = (CGRect){CGPointZero, screenSize()};
l2.mask = m2;
l3 = [CALayer layer];
// l3.rasterizationScale = screenScale(); (Doesn't work)
l3.contents = (__bridge id _Nullable)(textBG(color, screenSize()).CGImage);
l3.frame = (CGRect){CGPointZero, screenSize()};
l3.mask = m3;
UIColor* color2 = [lzyColors redColor];
l4 = [CALayer layer];
l4.contents = (__bridge id _Nullable)(colorImage([color2 lightenByValue:0.6], screenSize()).CGImage);
l4.frame = (CGRect){CGPointZero, screenSize()};
l4.mask = m4;
l5 = [CALayer layer];
l5.contents = (__bridge id _Nullable)(colorImage([color2 lightenByValue:0.3], screenSize()).CGImage);
l5.frame = (CGRect){CGPointZero, screenSize()};
l5.mask = m5;
l6 = [CALayer layer];
l6.contents = (__bridge id _Nullable)(colorImage(color2, screenSize()).CGImage);
l6.frame = (CGRect){CGPointZero, screenSize()};
l6.mask = m6;
[self addSublayer:l1]; [self addSublayer:l2]; [self addSublayer:l3]; [self addSublayer:l4]; [self addSublayer:l5]; [self addSublayer:l6];
CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"position"];
anim.fromValue = [NSValue valueWithCGPoint:(CGPoint){-pythag, -pythag}];
anim.toValue = [NSValue valueWithCGPoint:CGPointZero];
anim.delegate = self;
anim.beginTime = CACurrentMediaTime()+1;
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
anim.removedOnCompletion = NO;
anim.fillMode = kCAFillModeForwards;
anim.duration = 1;
[m1 addAnimation:anim forKey:@"0"];
anim.duration = 1.25;
[m2 addAnimation:anim forKey:@"1"];
anim.duration = 1.5;
[m3 addAnimation:anim forKey:@"2"];
anim.fromValue = [NSValue valueWithCGPoint:(CGPoint){pythag, pythag}];
anim.beginTime = CACurrentMediaTime()+2.5;
anim.duration = 1;
[m4 addAnimation:anim forKey:@"3"];
anim.duration = 1.25;
[m5 addAnimation:anim forKey:@"4"];
anim.duration = 1.5;
[m6 addAnimation:anim forKey:@"5"];
}
return self;
}
@end
我知道代码很粗糙,但我只是为了调试而对其进行了简化。
colorImage() 和 textBG() 函数只是做一些核心图形渲染来为 6 层生成 6 个图像。这不应该是问题的根源,因为绘图很简单,并且动画在开始前会延迟一秒钟。
我尝试仅将rasterizationScale 设置为显示文本的图层的屏幕比例,但这不起作用。
我还尝试通过移除第三层下方的两层来提高性能,一旦它完成动画,但它并没有显着提高性能。
-(void) animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
if (flag) {
if (i == 2) {
[l1 removeFromSuperlayer];
l1 = nil;
m1 = nil;
[l2 removeFromSuperlayer];
l2 = nil;
m2 = nil;
l3.mask = nil;
m3 = nil;
}
i++;
}
}
对如何提高性能有什么建议吗?
【问题讨论】:
-
我在您的帖子中看到的唯一内容是静止图像。您可以发布您创建的视频的链接吗?
-
如果您愿意接受预渲染(根据 Duncan 的回答中的 cmets),为什么不在图形应用程序中创建静态图像并从资产目录中加载它们呢?您的背景颜色可能仍然是随机的。这种技术没有那么灵活,但它的性能可能会更好。
-
嗯,在 1x、2x、3x、iPad、2x iPad 上会有 15 种随机颜色……所以如果动画在 40fps 时长 4 秒……那就需要 12,000 张图像预渲染...我只是不认为这是一个实用的解决方案。
-
此外,我总是更喜欢用 CG 或 CA 实际完成的稍微不那么流畅的动画,而不是导入资产目录,这样我可以更容易地证明我的应用程序,并且能够调整/随时更改动画。
-
哦,在动画的后半部分,我想使用应用背景颜色......所以它甚至不是我可以在不同应用中重复使用的解决方案......所以是的,绝对不是一个选项.
标签: ios objective-c performance core-animation calayer