Я пытаюсь использовать CAShapeLayer
для маскирования CALayer
в моем приложении iOS
, поскольку для маскирования изображения вместо маскировки изображения требуется меньшее количество CPU time
в bitmap 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
очень отсталый. Однако он мгновенно реагирует, если я маскирую его вручную в 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 Profiler
в Instruments
, но я не могу точно сказать, что именно вызывает его.
Я попытался установить shouldRasterize
на YES
как на layer
, так и на layer.mask
, но ни один из них не имеет никакого эффекта. Я не уверен, что делать.
Edit:
Я провел больше тестирования и обнаружил, что если я использую только обычный CALayer
для маскировки другого CALayer (layer.mask = someOtherLayer)
, у меня такие же проблемы с производительностью. Похоже, что проблема не специфична для CAShapeLayer
-rather, она специфична для свойства mask
CALayer
.
Изменить 2:
Поэтому, узнав больше об использовании Core Animation tool
в Instruments
, я узнал, что представление визуализируется за кадром при каждом его перемещении. Установка shouldRaster
на YES
при появлении касания и выключении при окончании нажатия делает вид зеленым (сохраняя кэш) в Instruments
, но производительность все еще ужасна. Я считаю, что это связано с тем, что, хотя представление кэшируется, если оно не непрозрачно, оно должно быть повторно отображено с каждым фреймом.
Одна вещь подчеркнуть заключается в том, что если в масках есть только несколько видов (скажем, даже около десяти), производительность довольно хорошая. Однако, когда вы увеличиваете это до 100 or more
, производительность отстает. Я предполагаю, что это происходит потому, что, когда кто-то перемещается над другими, все они должны быть повторно отображены.
Мое заключение таково: У меня есть один из двух вариантов.
Во-первых, должно быть какое-то время, чтобы надолго замаскировать представление (визуализировать его один раз и называть его хорошим). Я знаю, что это можно сделать с помощью графического или растрового контекстного маршрута, как показано в моем примере кода, но когда слой маскирует его представление, это происходит мгновенно. Когда я делаю это в растровом контексте, как показано, он довольно медленный (так как в нем почти невозможно даже сравнить, насколько он медленнее).
Во-вторых, должен быть некоторый способ faster
сделать это через трассировку контекста битмапа. Если есть эксперт в маскировке изображений или представлений, их помощь будет очень оценена.