Основная графика: промежутки между закругленными контурами при поглаживании - PullRequest
2 голосов
/ 22 марта 2012

Я использую Core Graphics для создания плавающего прямоугольника с закругленными углами на iphone. При наложении штрихов вдоль концентрических прямоугольников с закругленными углами, промежутки между штрихами неизменно появляются в углах. Эти же штрихи располагаются рядом на прямых участках.

Соответствующая выдержка из кода (посторонний код удален):

-(void)drawRect:(CGRect)rect {
    CGRect borderRect = CGRectInset(rect, 1.0, 1.0);
    UIBezierPath *borderPath = [UIBezierPath bezierPathWithRoundedRect:borderRect cornerRadius:6.0];
    [...]
    CGContextSetStrokeColorWithColor(context, bevelStrokeColor);
    CGContextSetLineWidth(context, 2.0);
    CGContextAddPath(context, borderPath.CGPath);
    CGContextStrokePath(context);
    [...]
    CGRect inlayRect = CGRectInset(rect, inlayPathInset, inlayPathInset);
    UIBezierPath *inlayPath = [UIBezierPath bezierPathWithRoundedRect:inlayRect cornerRadius:6.0];
    [...]
    CGContextSetStrokeColorWithColor(context, inlayStrokeColor);
    CGContextSetLineWidth(context, 2.0);
    CGContextAddPath(context, inlayPath.CGPath);
    CGContextStrokePath(context);
    [...]
}

Вот изображение:

enter image description here

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

Если бы я использовал только границу, я бы не возражал, но у меня есть несколько концентрических прямоугольников со скругленными углами, которые я тоже буду реализовывать, и этот пробел будет проблемой.

Редактировать: Исправлена ​​опечатка в коде, которая произошла при расшифровке.

Ответы [ 2 ]

3 голосов
/ 24 марта 2012

Если lineWidth одинаково для всех штрихов, настройка innerCornerRadius на (outerCornerRadius - lineWidth) появляется для получения желаемого эффекта; это особый случай. Если вы не верите в следующее, я призываю вас проверить это. Реальные отношения, регулирующие это, выглядят так:

l i = внутренняя ширина линии

l o = ширина внешней линии

r i = внутренний радиус угла

r o = внешний радиус угла

l i / 2 + r i = r o - l o / 2

Таким образом: r i = r o - (l i / 2 + l o / 2)

Если l i = l o = l, то: r i = r o - l

/*
 The following should be inserted into a UIView subclass that has a size of ~280, ~200.

 lineWidthInner/2 + radiusInner = radiusOuter - lineWidthOuter/2
 radiusInner = radiusOuter - (lineWidthOuter + lineWidthInner)/2

 That is to say that the inner corner radius is equal to the outer corner radius 
     minus the average of the lineWidth's.


 innerInsetMargin = outerInsetMargin + (lineWidthOuter + lineWidthInner)/2

 The amount a line must be inset (insetMargin) is the previous line's insetMargin + the 
     average of the previous and current lineWidth's.  In the case in which the 
     outermost line's outer edge touches the bound of rect, the insetMargin is equal 
     to the sum of all previous lineWidth's plus half of the current lineWidth.

 Shutting off anti-aliasing is required to prevent alpha-blending of the non-rectilinear 
     parts of the line with the background.  I am not sure how to gracefully sidestep this.
     Insights into this would be appreciated.
*/
-(void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, UIColor.blackColor.CGColor);
    CGContextFillRect(context, rect);
    CGContextSetShouldAntialias(context,NO);

    NSArray *colors = [NSArray arrayWithObjects:
                       (id)UIColor.greenColor.CGColor, 
                       (id)UIColor.lightGrayColor.CGColor, 
                       (id)UIColor.yellowColor.CGColor,
                       (id)UIColor.blueColor.CGColor,
                       (id)UIColor.redColor.CGColor, nil];

    //Change lineWidth, lineWidthIncrement, or currentCornerRadius as you see fit
    CGFloat lineWidthIncrement = 1.0;
    CGFloat lineWidth = 10.0;
    CGFloat currentCornerRadius = 100.0;
    CGFloat insetMargin = lineWidth/2;

    do {
        CGContextSaveGState(context);
        CGContextSetStrokeColorWithColor(context, (CGColorRef)[colors objectAtIndex:(lcv % colors.count)]);
        CGContextSetLineWidth(context, lineWidth);
        CGContextAddPath(context, [UIBezierPath bezierPathWithRoundedRect:CGRectInset(rect, insetMargin, insetMargin) cornerRadius:currentCornerRadius].CGPath);
        CGContextStrokePath(context);
        CGContextRestoreGState(context);

        lineWidth += lineWidthIncrement;
        currentCornerRadius -= 0.5 * (lineWidth + (lineWidth - lineWidthIncrement));//-0.5*(lwi+lwo)
        insetMargin += 0.5 * (lineWidth + (lineWidth - lineWidthIncrement));

    } while(currentCornerRadius>0);

}
2 голосов
/ 23 марта 2012

В этом случае ваш второй угловой радиус также должен быть вычтен с вашим набором inlaypathinset. Внутренний радиус должен быть меньше, иначе сегменты круга не будут точно концентрическими.

Если рядом с концентрическими вы хотите, чтобы касались оба закругленных прямоугольника, то на вставке должно быть среднее значение ширины обеих линий.

...