2013-05-02 7 views
12

Ich möchte zweifarbige Linien mit 1px Linien von 2 verschiedenen Farben zeichnen. Ich habe eine Menge Code, also setze ich es nach dem Versuch zu erklären.CALayer drawInContext kann keine 1px Linien auf Retina-Displays zeichnen

Wenn I uiview drawRect Methode verwenden, funktioniert es gut, wenn ich Anti-Aliasing ausschalten, aber wenn ich Nutzschicht der drawLayerInContext es zeigt entweder eine Normallinie oder 2 Gleise Linien 2px mit Anti-Aliasing off oder zwei halbtransparente Linien 2px mit Antialising auf.

ich es geschafft, ein ähnliches Verhalten als UIView des drawRect Methode zu erhalten, indem ein Bild mit einem benutzerdefinierten Kontext schaffen, in dem ich eine Skala angeben:

UIGraphicsBeginImageContextWithOptions([self bounds].size, NO, 0.f); // 0.f for scale means "scale for device's main screen". 

ich gerade möchte wissen, warum ich das nicht bekommen gleiches Verhalten in drawInContext und wenn es eine Möglichkeit gab, ähnliches Verhalten zu erhalten. Hier

ist der Code, der die doppelte Farbe Linie zieht:

void DRAW_DOUBLE_LINE(CGContextRef ctx, CGPoint startPoint, CGPoint endPoint, UIColor* topColor, UIColor* bottomColor) 
{ 
    UIGraphicsPushContext(ctx); 

    UIBezierPath *topLine = [[UIBezierPath alloc] init]; 
    CGPoint topLineStartPoint = startPoint; 
    CGPoint topLineEndPoint = endPoint; 
    [topLine moveToPoint:topLineStartPoint]; 
    [topLine addLineToPoint:topLineEndPoint]; 
    [topColor setStroke]; 
    topLine.lineWidth = 0.5; 
    [topLine stroke]; 

    UIBezierPath *bottomLine = [[UIBezierPath alloc] init]; 
    CGPoint bottomLineStartPoint = topLineStartPoint; 
    bottomLineStartPoint.y +=0.5; 
    CGPoint bottomLineEndPoint = topLineEndPoint; 
    bottomLineEndPoint.y +=0.5; 
    [bottomLine moveToPoint:bottomLineStartPoint]; 
    [bottomLine addLineToPoint:bottomLineEndPoint]; 
    [bottomColor setStroke]; 
    bottomLine.lineWidth = 0.5; 
    [bottomLine stroke]; 

    UIGraphicsPopContext(); 
} 

Mit dem drawRect Methode von UIView ich erhalten diese:

 
| Points y coordinate | Antialiasing | Result       | 
| ------------------- | ------------ | ------------------------------- | 
| 5     | NO   | 2 lines of 1 px: Bingo!   | 
| 5.25    | NO   | 2 lines of 1 px: Bingo!   | 
| 5.5     | NO   | 2 lines of 1 px: Bingo!   | 
| 5     | YES   | 3 half transparent lines of 1px | 
| 5.25    | YES   | 2 lines of 1 px: Bingo!   | 
| 5.5     | YES   | 3 half transparent lines of 1px | 

In einem CALayer mit drawInContext bekomme ich diese Ergebnisse

 
| Points y coordinate | Antialiasing | Result       | 
| ------------------- | ------------ | ------------------------------- | 
| 5     | NO   | 2 lines of 2 px     | 
| 5.25    | NO   | 1 line of 2 px     | 
| 5.5     | NO   | 1 line of 2 px     | 
| 5     | YES   | 2 half transparent lines of 2px | 
| 5.25    | YES   | 1 half transparent line of 2px | 
| 5.5     | YES   | 2 half transparent lines of 2px | 

Mit meinem benutzerdefinierten Kontext bekomme ich dies:

 
| Points y coordinate | Antialiasing | Result       | 
| ------------------- | ------------ | ------------------------------- | 
| 5     | NO   | 2 lines of 1 px: Bingo!  | 
| 5.25    | NO   | 2 lines of 1 px: Bingo!  | 
| 5.5     | NO   | 2 lines of 1 px: Bingo!  | 
| 5     | YES   | 3 half transparent lines of 1px | 
| 5.25    | YES   | 2 lines of 1 px: Bingo!  | 
| 5.5     | YES   | 3 half transparent lines of 1px | 

-Code für drawRect Umsetzung:

- (void)drawRect:(CGRect)rect 
{ 
    CGContextRef context = UIGraphicsGetCurrentContext(); 

    CGPoint startPoint = CGPointMake(0, 5); 
    CGPoint endPoint = CGPointMake(CGRectGetMaxX(self.bounds),5); 

    UIColor* topLineColor = [UIColor whiteColor]; 
    UIColor* bottomLineColor = [UIColor blackColor]; 

    DRAW_DOUBLE_LINE(context, startPoint, endPoint, topLineColor, bottomLineColor); 
} 

-Code für drawInContext Umsetzung:

-(void)drawInContext:(CGContextRef)ctx{ 
    CGPoint startPoint = CGPointMake(0, 5); 
    CGPoint endPoint = CGPointMake(CGRectGetMaxX(self.bounds),5); 

    UIColor* topLineColor = [UIColor whiteColor]; 
    UIColor* bottomLineColor = [UIColor blackColor]; 

    DRAW_DOUBLE_LINE(ctx, startPoint, endPoint, topLineColor, bottomLineColor); 
} 

-Code für die Implementierung kundenspezifischen Kontext in display Methode des CALayer:

-(void)display{ 

    if ([UIScreen instancesRespondToSelector:@selector(scale)]) { 
     UIGraphicsBeginImageContextWithOptions([self bounds].size, NO, 0.f); // 0.f for scale means "scale for device's main screen". 
    } else { 
     UIGraphicsBeginImageContext([self bounds].size); 
    } 

    CGContextRef context = UIGraphicsGetCurrentContext(); 

    CGPoint startPoint = CGPointMake(0, 5.25); 
    CGPoint endPoint = CGPointMake(CGRectGetMaxX(self.bounds),5.25); 
    UIColor* topLineColor = [UIColor whiteColor]; 
    UIColor* bottomLineColor = [UIColor blackColor]; 

    DRAW_DOUBLE_LINE(ctx, startPoint, endPoint, topLineColor, bottomLineColor); 

    UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    self.contents = (id)coloredImg.CGImage; 
} 
+0

Haben Sie versucht, 'contentsScale' zu ​​ändern? – cahn

Antwort

0

Ich würde vorschlagen, anstatt Linien zu zeichnen, füllen Sie einfach gefüllte Rechtecke der gewünschten Größe. Einer der schwierigsten Teile mit unterschiedlichen Auflösungen sind die Positionen der Start- und Endpunkte von Linien. Aber Rechtecke zeichnen ist viel einfacher.

Die Koordinaten für Rechtecke sind immer gerade, weil Sie auf die Kante und nicht auf die Mitte eines Pixels ausgerichtet sind.

0

Zeichnen und füllen Sie Rechtecke anstelle von Linien. Die Koordinaten für Rechtecke sollten immer am Rand eines Pixels und nicht im Mittelpunkt liegen.

1

NICHT 0,5 als Breite verwenden.

ersetzen 0.5 mit 1.0/[UIScreen mainScreen].scale

Wenn Sie auf Ebene zeichnen Sie 1 Pixel breite Linie bekommen.

0

Der beste Weg, den ich gefunden habe, um präzise/knackig aussehende 1px Linien sowohl auf der Netzhaut/nicht Retina zu erhalten und sie als 1px zu halten, auch wenn Sie hineinzoomen ist ein Shader zu schreiben. In meinem Fall habe ich OpenGL benutzt, aber ich glaube, dass du das mit Metal für CALayers machen kannst.Der grundlegende Prozess besteht darin, ein Rechteck mit der Höhe Null (oder die Breite Null, wenn die Linie vertikal ist) zu zeichnen und dann im Shader diese Punkte um die gewünschte Anzahl von Pixeln nach außen zu schieben.

hatte ich die Idee von hier: https://www.mapbox.com/blog/drawing-antialiased-lines/

Verwandte Themen