多个CALayer掩码导致性能问题

时间:2015-12-08 22:33:06

标签: ios objective-c performance core-animation calayer

我正在尝试使用6个CALayer对象创建一个相当简单的动画,每个对象都被一个路径遮住。但是,在尝试为它们制作动画时,我遇到了明显的延迟峰值。 Here is a video of the animation running.我可以通过将shouldRasterize设置为YES来提升效果,但是会导致文本出现像素化,如下图所示:

Horrible pixelation..

我可以通过将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()函数只需执行一些Core Graphics渲染即可生成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++;
    }
}

有关如何改善表现的任何建议?

2 个答案:

答案 0 :(得分:1)

我建议将图层和蒙版合成为静态图像并为其制作动画。那应该很快。

答案 1 :(得分:0)

好吧,在尝试了无数方法来尝试实现这个动画之后;我得出的结论是,我可能最好只是跳过openGL。这将允许我为更复杂的动画更好地解决问题创建一个更通用的解决方案。