2014-09-09 5 views
16

ich eine benutzerdefinierte UIView, die etwas in einem überschriebeniOS in CALayers drawInContext Zeichnung ist entweder pixelig oder verschwommen auf Retina

- (void)drawRect:(CGRect)rect 

das funktioniert gut und gibt scharfe Ergebnisse auf Retina-Bildschirme zieht.

Jetzt möchte ich jedoch die Eigenschaften, auf denen die Zeichnung basiert animiert werden. animierbaren Eigenschaften Erstellen scheint möglich zu sein, nur auf der CALayer, so dass anstelle die Zeichnung in UIView zu tun, erstelle ich eine benutzerdefinierte CALayer Unterklasse und führen Sie die Zeichnung im Innern

- (void) drawInContext:(CGContextRef)ctx 

verwende ich ziemlich genau die gleichen Zeichencode in diesem Funktion wie ich in der DrawRect-Funktion der benutzerdefinierten UIView verwendet.

Das Ergebnis sieht genauso aus - aber es ist nicht Retina-Auflösung aber pixelig (großer quadratischer Pixel)

wenn ich

self.contentsScale = [UIScreen mainScreen].scale; 

Zu Beginn meiner drawInContext Umsetzung setzen, dann anstelle einem pixelig Ergebnis, bekomme ich ein unscharfes Ergebnis (als ob das Rendering immer noch in Nicht-Retina-Auflösung durchgeführt wird und dann auf Retina-Auflösung hochskaliert wird).

Was ist die korrekte Methode zum Rendern von scharfen Retina-Pfaden in CALayers drawInContext?

sind hier einige Screenshots (die blaue Linie Teil der benutzerdefinierten Zeichnung in Frage ist das gelbe Teil nur ein Bild ist.) DrawRect

Gezeichnet innerhalb benutzerdefinierten UIView suchen:

enter image description here

innen Gezeichnet benutzerdefinierte CALayer des drawInContext:

enter image description here

Drawin zuerst innerhalb benutzerdefinierter CALayer des drawInContext, mit self.contentScale Einstellung:

enter image description here

Für Vollständigkeit, hier ist (eine abgespeckte Version des) Zeichencode:

//if drawing inside custom UIView sublcass: 
- (void)drawRect:(CGRect)rect 
{ 
    CGContextRef currenctContext = UIGraphicsGetCurrentContext(); 
    [[UIColor blackColor] set]; 

    CGContextSetLineWidth(currenctContext, _lineWidth); 
    CGContextSetLineJoin(currenctContext,kCGLineJoinRound); 

    CGContextMoveToPoint(currenctContext,x1, y1); 
    CGContextAddLineToPoint(currenctContext,x2, y2); 
    CGContextStrokePath(currenctContext); 
} 

//if drawing inside custom CALayer subclass: 
- (void) drawInContext:(CGContextRef)ctx { 
{ 
    //self.contentsScale = [UIScreen mainScreen].scale; 

    CGContextRef currenctContext = ctx; 
    CGContextSetStrokeColorWithColor(currenctContext, [UIColor blackColor].CGColor); 

    CGContextSetLineWidth(currenctContext, _lineWidth); 
    CGContextSetLineJoin(currenctContext,kCGLineJoinRound); 

    CGContextMoveToPoint(currenctContext,x1, y1); 
    CGContextAddLineToPoint(currenctContext,x2, y2); 
    CGContextStrokePath(currenctContext); 
} 

neu zu formulieren, was ich will erreichen : Ich möchte das gleiche knackige Retina-Rendering wie im UIView-Ansatz erzielen, aber beim Rendern in CALayer

+0

in Retina-Display, müssen Sie durch 2. – Bejibun

+0

nicht die Höhe und Breite multiplizieren, die Größe und die Position auf dem Bildschirm korrekt – user1282931

+0

meine ich den Bildschirm Sie sollten nur mit 2 multipliziert werden, weil Retina-Display doppelte Auflösung benötigt. – Bejibun

Antwort

8

Verwenden Sie shouldRasterize = YES in der Schicht? Versuchen Sie, die CALayer-Unterklasse zu zeichnen, aber setzen Sie rasterizationScale auf die Bildschirmskalierung.

+0

musste rasterizationScale auf Bildschirmskala * 4.0 setzen, um glatte Linien zu erhalten ... –

+0

@AndresCanella auf welchem ​​Gerät verwendeten Sie 4.0 für rasterizationScale? – Crashalot

+0

@Crashalot Ich endete mit Bildschirmskala * 2.0 auf i6. Ich verlor an 4.0 Knusprigkeit. –

3

Das Problem ist hier wahrscheinlich contentScale; Beachten Sie, dass die Inhaltsskala des Layers möglicherweise zurückgesetzt wird, wenn Sie dies einer benutzerdefinierten Ansicht zuweisen, indem Sie die layerClass-Funktion überschreiben. Es kann einige andere Fälle geben, in denen dies auch geschieht. Um sicherzugehen, legen Sie die Inhaltsskala erst fest, nachdem die Ebene zu einer Ansicht hinzugefügt wurde.

Versuchen Sie, die Skalierung des Hauptbildschirms während der Init-Methode Ihrer benutzerdefinierten Ansicht Ihrem benutzerdefinierten Layer zuzuordnen.In Swift 3, der wie folgt aussieht:

layer.contentsScale = UIScreen.mainScreen().scale 

Oder in Swift 4:

layer.contentsScale = UIScreen.main.scale 
+0

Schöner Fang! Danke, Mann –

3

Nach der Zugabe von Schicht zu seiner Superlayer. set shouldRasterize auf JA gesetzt contentsScale und resterizatioinScale auf Bildschirmformat:

[self.progressView.layer addSublayer:self.progressLayer]; 
self.progressLayer.shouldRasterize = YES; 
self.progressLayer.contentsScale = kScreenScale; 
self.progressLayer.rasterizationScale = kScreenScale; 

CABasicAnimation *animate = [CABasicAnimation animationWithKeyPath:@"progress"];// progress is a customized property of progressLayer 
animate.duration = 1.5; 
animate.beginTime = 0; 
animate.fromValue = @0; 
animate.toValue = @1; 
animate.fillMode = kCAFillModeForwards; 
animate.removedOnCompletion = NO; 
animate.repeatCount = HUGE_VALF; 
[self.progressLayer addAnimation:animate forKey:@"progressAnimation"];