【问题标题】:Core Graphics: Gaps between rounded paths when stroking核心图形:抚摸时圆形路径之间的间隙
【发布时间】:2012-04-07 08:46:46
【问题描述】:

我正在使用 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);
    [...]
}

这是一张图片:

我尝试了上面发布的代码的不同版本。我已经手动创建了路径,使用 UIBezierPath 实例方法来创建和绘制,并且我已经通过视图的图层以及其他一些想法以各种组合设置了cornerRadius。他们中的一些人改善了这些问题,但并没有得到消除。

如果我只使用边框,我不会介意,但我也将实施一些同心圆角矩形,这个差距将是一个问题。

编辑:更正了转录时出现的代码拼写错误。

【问题讨论】:

  • 这里只是猜测一下,因为我没有看到您的代码有问题,也无法从图片中看出,但是当实例化inlayPath 时变量cornerRadius 的值是多少?莫非是6.0之类的边框路径?因为您需要记住,borderPath 内侧的半径小于外侧的半径。因此,您的 inlayPaths 角半径需要小于 6.0。如果它等于或大于你所看到的效果。
  • 糟糕。我忘记将其编辑为 6.0。我把它从其他路径初始化中去掉了。他们都在 6 岁,但这是不对的。我现在正试图推导它背后的数学。如果我有什么想法,我会分享。

标签: iphone ios core-graphics rounded-corners quartz-2d


【解决方案1】:

在这种情况下,您的第二个角半径也必须与您的 inlaypathinset 相减。内半径必须更小,否则圆段不完全同心。

如果在同心旁边,您还希望两个圆角矩形都接触,则插图需要是两个线宽的平均值。

【讨论】:

  • 我找到了答案。这是错误的。半径肯定会减小,但这种关系在数学上要漂亮得多。如果允许,我会在 3 小时内发布我的。
  • 我很好奇,因为我很相信我的答案:-)
  • 你在正确的轨道上。如果你能说服我我错了,我会很乐意承认这一点。我的答案很快。
  • @RGuy8032 我真的很期待你数学上漂亮的答案,它在哪里?
  • 抱歉耽搁了。昨晚做了一些测试后,我似乎遇到了障碍。我正在修改我的论文。一旦我想出可信的东西,我会立即发布。
【解决方案2】:

如果lineWidth 对所有笔划都相同,则将innerCornerRadius 设置为(outerCornerRadius - lineWidth) 似乎会产生所需的效果;这是一个特例。如果您不相信以下内容,我鼓励您进行测试。支配这一点的真正关系似乎如下:

li = 线宽内

lo = 外线宽

ri = 内圆角半径

ro = 外圆角半径

li/2 + ri = ro - lo/2

因此: ri = ro - (li/2 + lo/2)

如果 li = lo = l 那么: ri = ro - 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);

}

【讨论】:

    猜你喜欢
    • 2012-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-17
    • 2013-12-25
    相关资源
    最近更新 更多