Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
689 views
in Technique[技术] by (71.8m points)

ios - Multiple CALayer masks causing performance issues

I am trying to create a fairly simple animation using 6 CALayer objects, each masked by a path. However, I am running into significant lag spikes when trying to animate them. Here is a video of the animation running. I am able to boost performance by setting shouldRasterize to YES, however it results in pixelation of the text, as you can see from this image:

Horrible pixelation..

I can correct the pixelation by setting the rasterizationScale to the screen scale, however that brings back the lag spikes that occurred without rasterization!

Here is my code:

@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

I know the code is very crude, but I've just simplified it for debugging.

The colorImage() & textBG() functions just do some Core Graphics rendering to produce the 6 images for the 6 layers. This shouldn't be the source of the problem as drawing is simple and the animation is delayed by a second before starting.

I tried only setting the rasterizationScale to the screen scale on layers that display text, but this didn't work.

I have also tried to improve performance by removing the two layers underneath the third layer, once it has finished animating, however it hasn't improved performance significantly.

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

Any suggestions on how to improve the performance?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I would suggest compositing your layers and masks into static images and animating those. That should be plenty fast.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...