2013-05-02 2 views
12

Я хочу нарисовать двойную цветную линию с линиями 1px из 2 разных цветов. У меня много кода, поэтому я ставил его, пытаясь объяснить.CALayer drawInContext не может нарисовать линии 1px на дисплеях сетчатки

Если я использую UIView drawRect метода работает хорошо, когда я выключаю антиалиасинг, но когда я использую слой drawLayerInContext он либо отображает один обычные линии, или 2 простых линии линии от 2px с сглаживанием от или две половин прозрачных линий 2px с antialising на.

мне удалось получить подобное поведение, чем метод DrawRect UIView путем создания изображения с настраиваемым контекстом, в котором можно указать масштаб:

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

Я просто хотел бы знать, почему я не получаю такое же поведение в drawInContext и если бы был способ получить подобное поведение.

Вот код, который рисует двойной цвет линии:

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

С drawRect методом UIView я получить это:

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

В CALayer с drawInContext я получаю эти результаты

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

Используя мой пользовательский контекст, я получаю следующее:

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

Код для drawRect реализации:

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

Код для drawInContext реализации:

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

Код для реализации пользовательского контекста в display методе 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

вы пробовали изменения 'contentsScale'? – cahn

ответ

0

Я бы предложил вместо рисования линий просто нарисовать заполненные прямоугольники нужного размера. Одной из сложнейших частей с разными разрешениями являются местоположения начальной и конечной точек линий. Но рисовать прямоугольники намного проще.

Координаты для прямоугольников всегда четные, поскольку вы нацеливаете край, а не центр пикселя.

0

Нарисуйте и заполните прямоугольники вместо линий. Координаты для прямоугольников всегда должны быть на краю пикселя, а не центра.

1

НЕ ИСПОЛЬЗУЙТЕ 0,5 в качестве ширины.

заменить 0.5 с 1.0/[UIScreen mainScreen].scale

Когда вы рисуете на слое, который вы можете получить 1 пиксель шириной линии.

0

Лучший способ, который я нашел, чтобы получить четкие/четкие линии 1px на сетчатке и не сетчатке и поддерживать их как 1px, даже если вы увеличиваете масштаб, это писать шейдер. В моем случае я использовал OpenGL, но я считаю, что вы можете сделать это с помощью Metal for CALayers.Основной процесс состоит в том, чтобы нарисовать прямоугольник нулевой высоты (или нулевую ширину, если линия вертикальна), а затем в шейдере надавите эти точки наружу на нужное количество пикселей.

Я пришла в голову мысль отсюда: https://www.mapbox.com/blog/drawing-antialiased-lines/

Смежные вопросы