2012-10-14 17 views
15

Ich möchte eine sehr dünne Haarlinie Breite einer Linie in meiner UIWiew DrawRect-Methode zeichnen. Die Zeile, die ich sehe, die einen Wert 0,5 für CGContextSetLineWidth hat, stimmt nicht mit dem gleichen Wert 1.0 Breite überein, der verwandt wird, um einen Rahmen CALayer zu zeichnen.Zeichnen einer sehr dünnen Linie mit CGContextAddLineToPoint und CGContextSetLineWidth

Sie können den Unterschied zwischen den beiden sehen - die rote Linie (Breite = 1) ist viel dünner als die lila/blaue Linie (Breite = 0,5).

Border drawn with CALayer

Hier ist, wie ich meine Pseudo 1.0 Breite horizontale Linie an Zeichnung:

CGContextRef ctx = UIGraphicsGetCurrentContext(); 
CGContextSetStrokeColorWithColor(ctx, [UIColor blueColor].CGColor); 
CGContextSetLineWidth(ctx, 0.5); // I expected a very thin line 

CGContextMoveToPoint(ctx, 0, y); 
CGContextAddLineToPoint(ctx, self.bounds.size.width, y); 

CGContextStrokePath(ctx); 

Hier ist eine Grenze für die gleiche Ansicht, diesmal unter Verwendung von 1,0 Randbreite:

UIView *myView = (UIView *)self; 
CALayer *layer = myView.layer; 
layer.borderColor = [UIColor redColor].CGColor; 
layer.borderWidth = 1.0; 

Was muss ich anders machen, um meine eigene benutzerdefinierte Linie zu zeichnen, die die gleiche Breite wie die CALayer-Version hat?

Antwort

38

Wenn Sie einen Pfad streichen, spreizt der Strich den Pfad. Um es anders auszudrücken, der Pfad liegt in der Mitte des Strichs.

Wenn der Pfad entlang der Kante zwischen zwei Pixeln verläuft, bedeckt der Strich (teilweise) die Pixel auf beiden Seiten dieser Kante. Bei einer Linienbreite von 0,5 erweitert sich ein horizontaler Strich um 0,25 Punkte in den Pixel über dem Pfad und um 0,25 Punkte in den Pixel unter dem Pfad.

Sie müssen Ihren Weg bewegen, damit es nicht am Rande des Pixels läuft:

CGFloat lineWidth = 0.5f; 
CGContextSetLineWidth(ctx, lineWidth); 

// Move the path down by half of the line width so it doesn't straddle pixels. 
CGContextMoveToPoint(ctx, 0, y + lineWidth * 0.5f); 
CGContextAddLineToPoint(ctx, self.bounds.size.width, y + lineWidth * 0.5f); 

Aber da Sie nur eine horizontale Linie zu zeichnen, ist es einfacher zu bedienen CGContextFillRect:

CGContextSetFillColorWithColor(ctx, [UIColor blueColor].CGColor); 
CGContextFillRect(ctx, CGRectMake(0, y, self.bounds.size.width, 0.5f)); 
+0

Es ist eine Art Magie! Es funktioniert, aber könnten Sie mir erklären, warum ich den Pfad um die Hälfte der Linienbreite nach unten verschieben sollte oder einen Link geben soll? – PSsam

+6

http://stackoverflow.com/a/13674460/77567 –

+0

Aber er hat es so klar erklärt, in 6 klaren Textzeilen ... Vermeiden Sie das Überspreizen der Pixelgrenzen beim Zeichnen dünner Linien. Das Antialiasing des Zeichenmechanismus erzeugt eine "verschmierte" Linie, die optisch dicker aussieht als erwartet, aber nicht. –

16

Sie müssen Antialiasing ausschalten, um eine dünne Linie zu erhalten, wenn nicht auf einem Integral gezeichnet.

CGContextSetShouldAntialias(ctx, NO) 
+0

Das machte meinen Tag :-) – Bartserk

+0

Froh, mir behilflich zu sein, habe ich oft selbst die Antialias übersehen. – Conor

+0

Ich arbeitete dies auf einer iOS7 App, 1 Pixelzeile in Retina, dieser Befehl hatte keine Auswirkungen. YMMV. –