2013-05-02 12 views
12

Chcę narysować podwójnie zabarwioną linię z 1px liniami 2 różnych kolorów. Mam dużo kodu, więc umieszczam go po próbie wyjaśnienia.CALayer drawInContext nie może narysować linii 1px na wyświetlaczach siatkówki

Jeśli używam UIView drawRect metoda działa dobrze, kiedy wyłączyć antyaliasing ale kiedy używam warstwy drawLayerInContext to albo wyświetla jeden szlakowego lub 2 zwykły linia linie o 2px antyaliasing off lub dwóch pół przezroczyste linie 2px z antialising na.

udało mi się uzyskać podobne zachowanie niż metody UIView za drawRect tworząc obraz z kontekstu niestandardowego gdzie mogę określić skalę:

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

Chciałbym tylko wiedzieć, dlaczego nie dostać to samo zachowanie w drawInContext i czy istnieje sposób na uzyskanie podobnego zachowania.

Oto kod, który zwraca podwójną linię kolorów:

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(); 
} 

Dzięki metodzie drawRect z UIView mogę uzyskać to:

 
| 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 | 

W CALayer z drawInContext uzyskać te wyniki

 
| 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 | 

Korzystanie z mojego kontekstu niestandardowego Otrzymuję to:

 
| 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 | 

Kod drawRect realizacji:

- (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); 
} 

kodują drawInContext realizacji:

-(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); 
} 

Kod dla realizacji kontekstowego zwyczaj w display metody CALayer za:

-(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

próbowałeś zmieniając 'contentsScale'? – cahn

Odpowiedz

0

Proponuję zamiast rysować linie, po prostu rysuj wypełnione prostokąty o pożądanym rozmiarze. Jedną z trudnych części o różnych rozdzielczościach są lokalizacje punktów początkowych i końcowych linii. Ale rysowanie prostokątów jest znacznie łatwiejsze.

Współrzędne dla prostokątów są zawsze równe, ponieważ kierujesz na krawędź, a nie środek piksela.

0

Rysuj i wypełniaj prostokąty zamiast linii. Współrzędne prostokąta powinny zawsze znajdować się na krawędzi piksela, a nie na środku.

1

NIE UŻYWAJ 0,5 jako szerokości.

zastąpić 0.5 z 1.0/[UIScreen mainScreen].scale

Podczas rysowania na warstwie można uzyskać 1 piksela szerokości linii.

0

Najlepszy sposób, w jaki udało mi się uzyskać precyzyjne/wyraźne linie 1px na obu siatkówkach/nie-siatkówce i utrzymać je jako 1 piksel, nawet przy powiększeniu, to napisanie modułu cieniującego. W moim przypadku korzystałem z OpenGL, ale wierzę, że można to zrobić z Metalem dla CALayers.Podstawowym procesem jest narysowanie prostokąta o zerowej wysokości (lub zerowej szerokości, jeśli linia jest pionowa), a następnie w module cieniującym przesuń te punkty na zewnątrz o pożądaną liczbę pikseli.

mam pojęcia, stąd: https://www.mapbox.com/blog/drawing-antialiased-lines/

Powiązane problemy