问题描述
我发布此问题是为了回应上一个问题的:
I am posting this question in response to one of the answers on my previous question here: Multiple CALayer masks causing performance issues
所以,既然我试图按照预先渲染的动画方法,我仍然无法获得平滑的动画。不仅如此,但是当在实际设备上运行时,应用程序会因内存问题而定期崩溃。
So, now that I am attempting to go down the pre-rendered animation approach, I am still unable to get a smooth animation. Not only that, but when run on an actual device, the app crashes periodically due to memory issues.
您可以在此处看到运行的动画:(从视频看起来可能不是那么糟糕,但专注于动画的边缘,它在实际设备上表现更差。)
You can see the animation running here: http://cl.ly/e3Qu (It may not look so bad from the video, but focus on the edge of animation, and it performs worse on an actual device.)
这是我的代码:
static CGFloat const animationDuration = 1.5;
static CGFloat const calculationRate = (1.0/40.0); // 40fps max.
static CGFloat const calculationCycles = animationDuration/calculationRate;
@implementation splashView {
CADisplayLink* l;
CGImageRef backgroundImg;
UIColor* color;
NSMutableArray* animationImages;
NSTimeInterval currentTime;
}
-(void) beginAnimating {
static dispatch_once_t d;
dispatch_once(&d, ^{
CGFloat totalDistance = 0;
CGFloat screenProgress = 0;
CGFloat deltaScreenProgress = 0;
totalDistance = screenHeight()+screenWidth();
color = [[lzyColors colors] randomColor];
backgroundImg = textBG(color, screenSize()).CGImage;
animationImages = [NSMutableArray array];
NSLog(@"start");
UIGraphicsBeginImageContextWithOptions(screenSize(), YES, 0);
CGContextRef c = UIGraphicsGetCurrentContext();
for (int i = 0; i <= (calculationCycles+1); i++) {
UIImage* img = lzyCGImageFromDrawing(^{
CGFloat height = screenHeight();
CGFloat width = screenWidth();
CGMutablePathRef p = CGPathCreateMutable();
CGPoint startingPoint = [self pointBForProgress:screenProgress];
CGPathMoveToPoint(p, nil, startingPoint.x, startingPoint.y);
lzyCGPathAddLineToPath(p, [self pointAForProgress:screenProgress]);
if ((width < screenProgress) && (screenProgress-deltaScreenProgress) < width) {
lzyCGPathAddLineToPath(p, (CGPoint){width, 0});
}
if (deltaScreenProgress != 0) lzyCGPathAddLineToPath(p, [self pointAForProgress:screenProgress-deltaScreenProgress-1]);
if (deltaScreenProgress != 0) lzyCGPathAddLineToPath(p, [self pointBForProgress:screenProgress-deltaScreenProgress-1]);
if ((height < screenProgress) && (screenProgress-deltaScreenProgress) < height) {
lzyCGPathAddLineToPath(p, (CGPoint){0, height});
}
CGPathCloseSubpath(p);
CGContextAddPath(c, p);
CGContextClip(c);
CGPathRelease(p);
CGContextSetFillColorWithColor(c, color.CGColor);
CGContextFillRect(c, self.bounds);
CGContextDrawImage(c, self.bounds, backgroundImg);
});
[animationImages addObject:img];
deltaScreenProgress = screenProgress;
screenProgress = (i*totalDistance)/calculationCycles;
deltaScreenProgress = screenProgress-deltaScreenProgress;
}
NSLog(@"stop");
currentTime = 0;
l = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkDidFire)];
[l addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
});
}
-(void) displayLinkDidFire {
NSTimeInterval deltaTime = l.duration;
currentTime += deltaTime;
if (currentTime <= animationDuration) {
CGFloat prg = (currentTime/animationDuration);
NSInteger image = roundf(([animationImages count]-1)*prg);
[CATransaction begin];
[CATransaction setDisableActions:YES];
self.layer.contents = (__bridge id _Nullable)(((UIImage*)[animationImages objectAtIndex:image]).CGImage);
[CATransaction commit];
} else {
[CATransaction begin];
[CATransaction setDisableActions:YES];
self.layer.contents = (__bridge id _Nullable)(((UIImage*)[animationImages lastObject]).CGImage);
[CATransaction commit];
[l invalidate];
animationImages = nil;
}
}
-(CGPoint) pointAForProgress:(CGFloat)progressVar {
CGFloat width = screenWidth();
return (CGPoint){(progressVar<width)?progressVar:width+1, (progressVar>width)?progressVar-width:-1};
}
-(CGPoint) pointBForProgress:(CGFloat)progressVar {
CGFloat height = screenHeight();
return (CGPoint){(progressVar>height)?(progressVar-height):-1, (progressVar<height)?progressVar:height+1};
}
@end
textBG()
函数只是做一些相当简单的Core Graphics绘图来获取背景图像。
The textBG()
function just does some fairly simple Core Graphics drawing to get the background image.
我只能假设我在做某事这里根本就错了,但我想不出它是什么。
I can only assume I'm doing something fundamentally wrong here, but I can't think of what it is.
关于如何提高性能和减少内存消耗的任何建议(不降低动画质量) ?
Any suggestions on how to improve performance and reduce memory consumption (without degrading the quality of the animation)?
推荐答案
通过图层内容动画全屏图像肯定会出现性能和内存问题,尤其是在@ 3x设备上。对于您在另一个问题中显示的动画(),看起来您实际上并不需要任何掩蔽 - 创建一系列矩形纯色层(黑色,浅紫色,中紫色,深紫色),从前到后分层(文本层位于浅色和中间层之间),将它们旋转到你需要的角度,并根据需要移动它们。
Animating a full-screen image via layer contents is definitely going to have performance and memory problems, especially on @3x devices. For the animation you’re showing in the other question (this video), it doesn’t look like you actually need any masking at all—create a series of rectangular solid-colored layers (black, light purple, medium purple, dark purple), layer them from front to back (with the text layer in between the light and medium ones), rotate them to the angle you need, and move them around as needed.
如果你最终需要一个更复杂的动画,这种方法不适用于 - 或者一般来说,动画任意全屏内容 - 您需要(1)将其预渲染为视频(离线或使用AVFoundation API)并以此方式播放或(2)使用OpenGL或Metal进行绘制。
If you end up needing a more complicated animation that that approach won’t work for—or in general, for animating arbitrary full-screen content—you’ll need to either (1) pre-render it as a video (either offline or using the AVFoundation APIs) and play it back that way or (2) use OpenGL or Metal to do the drawing.
这篇关于预渲染的核心图形动画不能平滑地制作动画。猪的记忆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!