Search code examples
ioscore-graphicsuibezierpath

How to stroke the boundary of a uibezierpath on the inside of the path?


Usually, when we draw a bezierpath in CoreGraphics, and set this 'CGContextSetLineWidth' a the desired thickness of the path , it strokes on the outside boundary of the path ( as the line width increases, the boundary seems to grow on the outside of the path), I want my line thickness to grow on the inside of the bezier path, is there a way to do that?


Solution

  • I am not aware of a way to stroke the inside of a path. However, you can accomplish something similar, which might work for you. If you scale down the path and move it to the center with the correct amount, it will fit nicely within the bounds you want. The visual difference between drawing inside and scaling is none for simple shapes like rectangles, rounded rects and ellipses, but will differ for more complex shapes. Consider what will happen if you stroke the letter B with "inside strokes", versus scaling it.

    Here is what it looks like before and after transforming using a very wide line. As you can see, stroking a line will center it on the path, making half of it appear on each side. So to transform it, we will need to move the path by half a line width down and right, then scale it down by the line width.

    Using bezierPathWithRoundedRect
    line width 20, box size 200 x 300, corner radius 50

    paths

    The transform then becomes like this.

    viewSize is your bounding box for the path
    lineWidth is the width of the line
    bezierPath is your UIBezierPath

    CGAffineTransform transform = CGAffineTransformMakeTranslation(lineWidth / 2.0,
                                                                   lineWidth / 2.0);
    transform = CGAffineTransformScale(transform, 
                                       (viewSize.width - lineWidth) / viewSize.width, 
                                       (viewSize.height - lineWidth) / viewSize.height);
    
    CGPathRef reducedPath = CGPathCreateCopyByTransformingPath(bezierPath.CGPath, &transform);
    


    UPDATE

    If you want to keep the aspect ratio, the scaling can be modified to be equal on both axis, using the smallest factor on both.

    CGFloat scale = viewSize.width < viewSize.height ? (viewSize.width - lineWidth) / viewSize.width :
                                                       (viewSize.height - lineWidth) / viewSize.height;
    
    CGAffineTransform transform = CGAffineTransformMakeTranslation(lineWidth / 2.0, lineWidth / 2.0);
    transform = CGAffineTransformScale(transform, scale, scale);
    
    CGPathRef reducedPath = CGPathCreateCopyByTransformingPath(bezierPath.CGPath, &transform);