23

我正在尝试在我的应用程序中使用CAShapeLayer遮罩 a ,因为它需要一小部分来遮罩图像而不是手动遮罩 a 中的图像;CALayeriOSCPU timebitmap context

当我有几十个或更多图像相互叠加时,CAShapeLayer蒙版UIImageView移动到我的触摸时很慢。

这是一些示例代码:

UIImage *image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"SomeImage.jpg" ofType:nil]];
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddEllipseInRect(path, NULL, CGRectMake(0.f, 0.f, image.size.width * .25, image.size.height * .25));

for (int i = 0; i < 200; i++) {

    SLTUIImageView *imageView = [[SLTUIImageView alloc]initWithImage:image];
    imageView.frame = CGRectMake(arc4random_uniform(CGRectGetWidth(self.view.bounds)), arc4random_uniform(CGRectGetHeight(self.view.bounds)), image.size.width * .25, image.size.height * .25);

    CAShapeLayer *shape = [CAShapeLayer layer];
    shape.path = path;
    imageView.layer.mask = shape;

    [self.view addSubview:imageView];
    [imageView release];

}
CGPathRelease(path);

用上面的代码,imageView很卡顿。但是,如果我在 a 中手动屏蔽它,它会立即做出反应bitmap context

UIImage *image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"3.0-Pad-Classic0.jpg" ofType:nil]];
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddEllipseInRect(path, NULL, CGRectMake(0.f, 0.f, image.size.width * .25, image.size.height * .25));


for (int i = 0; i < 200; i++) {

    UIGraphicsBeginImageContextWithOptions(CGSizeMake(image.size.width * .25, image.size.height * .25), NO, [[UIScreen mainScreen]scale]);
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    CGContextAddPath(ctx, path);
    CGContextClip(ctx);

    [image drawInRect:CGRectMake(-(image.size.width * .25), -(image.size.height * .25), image.size.width, image.size.height)];
    UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    SLTUIImageView *imageView = [[SLTUIImageView alloc]initWithImage:finalImage];
    imageView.frame = CGRectMake(arc4random_uniform(CGRectGetWidth(self.view.bounds)), arc4random_uniform(CGRectGetHeight(self.view.bounds)), finalImage.size.width, finalImage.size.height);

    [self.view addSubview:imageView];
    [imageView release];

}
CGPathRelease(path);

顺便说一句,这是 的代码SLTUIImageView,它只是UIImageView响应触摸的一个简单子类(对于任何想知道的人):

-(id)initWithImage:(UIImage *)image{

    self = [super initWithImage:image];
    if (self) {
        self.userInteractionEnabled = YES;
    }
    return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    [self.superview bringSubviewToFront:self];
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{

    UITouch *touch = [touches anyObject];
    self.center = [touch locationInView:self.superview];
}

是否有可能以某种方式优化CAShapeLayer掩蔽的方式UIImageView以提高性能?我试图找出瓶颈在哪里使用Time Profilerin Instruments,但我无法确切说明是什么原因造成的。

我已经尝试同时设置shouldRasterizeYES设置layerlayer.mask但似乎都没有任何效果。我不知道该怎么办。

编辑:

我做了更多的测试,发现如果我只使用一个普通CALayer的来掩盖另一个CALayer (layer.mask = someOtherLayer)我有同样的性能问题。似乎问题不是特定于 -CAShapeLayer而是特定maskCALayer.

编辑2:

因此,在了解了有关使用Core Animation toolin的更多信息后Instruments,我了解到视图每次移动时都会呈现在屏幕外。设置shouldRasterYES触摸开始时并在触摸结束时关闭它会使视图保持绿色(从而保持缓存)instruments,但性能仍然很糟糕。我相信这是因为即使视图正在被缓存,如果它不是不透明的,那么它仍然必须在每一帧中重新渲染。

需要强调的一件事是,如果只有几个视图被屏蔽(甚至十个左右),则性能非常好。但是,当您将其增加到 时100 or more,性能会滞后。我想这是因为当一个人越过其他人时,他们都必须重新渲染。

我的结论是,我有两种选择之一。

首先,必须有某种方式永久屏蔽视图(渲染一次并称其为良好)。我知道这可以通过我在示例代码中显示的图形或位图上下文路由来完成,但是当图层掩盖其视图时,它会立即发生。当我在如图所示的位图上下文中执行此操作时,它非常慢(因为它几乎无法比较它有多慢)。

其次,必须有某种faster方法可以通过位图上下文路由来实现。如果有屏蔽图像或视图的专家,将非常感谢他们的帮助。

4

2 回答 2

1

你已经走了很远,我相信几乎是一个解决方案。我要做的只是您已经尝试过的扩展。由于您说其中许多图层“结束”在相对于其他图层和蒙版保持不变的最终位置。所以只需将所有这些“完成”图层渲染到单个位图上下文。那样的话,每次你写一个层到那个单一的上下文时,你会少一个层来担心会减慢动画/渲染过程。

于 2017-07-06T13:18:23.093 回答
0

Quartz (drawRect:) 比 CoreAnimation 慢的原因有很多:CALayer vs CGContext drawRect vs CALayer。但有必要正确使用它。

在文档中,您可以看到一些建议。提高CoreAnimationPerformance

如果您想要高性能,也许您可​​以尝试使用AsyncDisplayKit。该框架允许创建流畅且响应迅速的应用程序。

于 2017-07-20T14:46:10.057 回答