ios - 多个 CALayer 蒙版导致性能问题

标签 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++;
    }
}

关于如何提高性能有什么建议吗?

最佳答案

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

关于ios - 多个 CALayer 蒙版导致性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34167360/

相关文章:

MySQL - 选择关系数据避免左连接的最快方法

ios - UINavigationController pushViewController 在中途暂停/卡住

ios - 如何在 SwiftUI 的 NavigationView 中放置 Logo ?

objective-c - IBDesignable 在 Objective-C 中不起作用

javascript - 如何分析/减少 html 页面渲染时间?

c - 哪个更快 : bitshift vs switch

iOS 方向改变,但页面仍然垂直

ios - 从 Web 服务获取数组到 pickerview

ios - 按顺序循环数组并重复

objective-c - cache_eraseImp_nolock 在 iOS 7 中花费很长时间