Ich versuche CAShapeLayer
zu verwenden, um ein CALayer
in meinen iOS
App zu maskieren, da es einen Bruchteil der CPU time
nimmt ein Bild manuell zu maskieren vs man in einer Maskierung bitmap context
;Leistungsprobleme, wenn viele CALayer Masken
Wenn ich mehrere Dutzend oder mehr Bilder übereinander geschichtet habe, ist die CAShapeLayer
maskierte UIImageView
langsam auf meine Berührung zu bewegen. Hier
ist einige Beispiel-Code:
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);
Mit dem obigen Code, imageView
sehr laggy ist. Es ist jedoch reagiert sofort, wenn ich es manuell in einer bitmap context
Maske:
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);
By the way, hier ist der Code zu SLTUIImageView
, es ist nur eine einfache Unterklasse von UIImageView
, die (für jeden, der frage mich) auf Berührungen reagiert :
-(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];
}
ist es möglich, irgendwie zu optimieren, wie die CAShapeLayer
die UIImageView
maskiert, so dass die Leistung verbessert wird? Ich habe versucht, herauszufinden, wo der Flaschenhals die Time Profiler
in Instruments
verwendet, aber ich kann nicht genau sagen, was es verursacht.
Ich habe versucht, shouldRasterize
zu YES
sowohl auf layer
als auch auf layer.mask
zu setzen, aber keiner scheint irgendeinen Effekt zu haben. Ich bin mir nicht sicher, was ich tun soll.
Edit:
Ich habe mehr Tests durchgeführt und finden, dass, wenn ich nur eine ganz normale CALayer
verwenden Sie einen anderen CALayer (layer.mask = someOtherLayer)
ich die gleichen Performance-Probleme haben zu maskieren. Es scheint, dass das Problem nicht spezifisch ist für CAShapeLayer
-aber es ist spezifisch für die mask
Eigenschaft von CALayer
.
Edit 2:
So nach mehr über die Verwendung der Core Animation tool
in Instruments
lernen, habe ich gelernt, dass die Ansicht außerhalb des Bildschirms jedes Mal bewegt gerendert wird. Die Einstellung shouldRaster
auf YES
, wenn die Berührung anfängt und sie ausschaltet, wenn die Berührung endet, lässt die Ansicht in instruments
grün bleiben (also den Cache behalten), aber die Leistung ist immer noch schrecklich. Ich glaube, das liegt daran, dass, obwohl die Ansicht zwischengespeichert wird, wenn sie nicht undurchsichtig ist, sie immer noch mit jedem Bild neu gerendert werden muss.
Eine Sache zu betonen ist, dass, wenn es nur ein paar Ansichten maskiert sind (sagen, sogar um zehn) die Leistung ist ziemlich gut. Wenn Sie das jedoch auf 100 or more
erhöhen, bleibt die Leistung zurück. Ich stelle mir das vor, denn wenn man sich über die anderen bewegt, müssen sie alle neu gerendert werden.
Mein Fazit ist dies, Ich habe eine von zwei Möglichkeiten.
Zuerst muss es eine Möglichkeit geben, eine Ansicht dauerhaft zu maskieren (einmal rendern und gut nennen).Ich weiß, dass dies über die Grafik- oder Bitmapkontextroute geschehen kann, wie ich in meinem Beispielcode zeige, aber wenn eine Ebene ihre Ansicht maskiert, geschieht dies sofort. Wenn ich es in einem Bitmap-Kontext wie gezeigt mache, ist es ziemlich langsam (da es fast nicht einmal verglichen werden kann, wie viel langsamer es ist).
Zweitens muss es einige faster
Möglichkeit geben, es über die Bitmap-Kontext-Route zu tun. Wenn es einen Experten gibt, Bilder oder Ansichten zu maskieren, würde ihre Hilfe sehr geschätzt werden.
Ihre beste Wette ist in der Tat zu komprimieren Sie Ihre 200 Bilder, die Sie in Ihrer For-Schleife in 1 großes Bild mit etwas wie der Code hier erwähnt: http://stackoverflow.com/questions/4334233/how-to-capture- uiview-to-uiimage-ohne-verlust-von-qualität-auf-retina-display Sie könnten auch versuchen, Instrumente zu verwenden und den Zeitprofiler verwenden, um zu überprüfen, wo der Flaschenhals Ihres Codes ist. –
Haben Sie versucht, die Bilder im Voraus in ihren endgültigen benötigten Zustand zu rendern, bevor Sie sie in der App verwenden, so dass die App nicht all diese Grafikverarbeitung durchführen muss, insbesondere da Sie so viele Bilder haben, um diese Verarbeitung durchzuführen Sie werden herumbewegt, so dass sie alle ständig neu rendern müssen. Ich bin mir nicht sicher, ob das eine brauchbare Option für Sie ist und ob Sie es schon versucht haben. Es ist auch schwierig zu erfassen, was Sie mit den Bildern ohne ein Bild zu tun versuchen, in diesem Fall ist es wichtig, wenn Sie einen Screenshot anhängen, würde es helfen. –
Dies liegt an dem Offscreen-Rendering, auf das Sie bereits hingewiesen haben. Ich glaube nicht, dass es einen Weg gibt, um die Leistung der Ebene zu optimieren, aber wie Sie bereits gesehen haben, können Sie den Prozess optimieren. Ein weiterer Schritt könnte sein, dass die UIView-Klasse die DrawRect überschreibt, um das zu erreichen, was Sie brauchen. Der DrawRect wird nur aufgerufen, wenn Ihre Ansicht als schmutzig markiert ist. Keine Unterklasse UIImageView bacuse drawRect wird nie aufgerufen. – Andrea