Actually duplicate / extract Apple's "continuous corners for iPhoneX"?

I wrote an experimental class which constructs a bezier path which overlaps the border of a CALayer due to @Aflah Bhari's comments. The layer has set its private property continuousCornersto YES. This is the result:

Layer and Path

The border of the layer is blue while the color of the path is red.

Here is the code. You can set radius and insets in attribute inspector of Interface Builder. I have created the image above by setting the class of the view controllers view to ArcView, its radius to 30.0 and the insets to (20.0, 20.0).

Here is the code:

ArcView.h

IB_DESIGNABLE
@interface ArcView : UIView

@property(nonatomic) IBInspectable CGFloat radius;
@property(nonatomic) IBInspectable CGSize insets;

@end

ArcView.m

#import "ArcView.h"

@interface CALayer(Private)

@property BOOL continuousCorners;

@end

@interface ArcView()

@property (strong) CALayer *borderLayer;

@end


@implementation ArcView

- (void)setRadius:(CGFloat)inRadius {
    if(_radius != inRadius) {
        _radius = inRadius;
        self.borderLayer.cornerRadius = inRadius;
        [self setNeedsDisplay];
    }
}

- (void)setInsets:(CGSize)inInsets {
    if(!CGSizeEqualToSize(_insets, inInsets)) {
        _insets = inInsets;
        [self setNeedsLayout];
        [self setNeedsDisplay];
    }
}

- (void)awakeFromNib {
    [super awakeFromNib];
    self.borderLayer = [CALayer new];
    self.borderLayer.borderColor = [[UIColor blueColor] CGColor];
    self.borderLayer.borderWidth = 0.5;
    self.borderLayer.continuousCorners = YES;
    self.borderLayer.cornerRadius = self.radius;
    [self.layer addSublayer:self.borderLayer];
}

- (void)layoutSubviews {
    [super layoutSubviews];
    self.borderLayer.frame = CGRectInset(self.bounds, self.insets.width, self.insets.height);
}

- (void)drawRect:(CGRect)rect {
    CGFloat theRadius = self.radius;
    CGFloat theOffset = 1.2 * theRadius;
    CGRect theRect = CGRectInset(self.bounds, self.insets.width, self.insets.height);
    UIBezierPath *thePath = [UIBezierPath new];
    CGPoint thePoint;

    [thePath moveToPoint:CGPointMake(CGRectGetMinX(theRect) + theOffset, CGRectGetMinY(theRect))];
    [thePath addLineToPoint:CGPointMake(CGRectGetMaxX(theRect) - theOffset, CGRectGetMinY(theRect))];
    thePoint = CGPointMake(CGRectGetMaxX(theRect), CGRectGetMinY(theRect));
    [thePath addQuadCurveToPoint:CGPointMake(CGRectGetMaxX(theRect), CGRectGetMinY(theRect) + theOffset) controlPoint:thePoint];
    [thePath addLineToPoint:CGPointMake(CGRectGetMaxX(theRect), CGRectGetMaxY(theRect) - theOffset)];
    thePoint = CGPointMake(CGRectGetMaxX(theRect), CGRectGetMaxY(theRect));
    [thePath addQuadCurveToPoint:CGPointMake(CGRectGetMaxX(theRect) - theOffset, CGRectGetMaxY(theRect)) controlPoint:thePoint];
    [thePath addLineToPoint:CGPointMake(CGRectGetMinX(theRect) + theOffset, CGRectGetMaxY(theRect))];
    thePoint = CGPointMake(CGRectGetMinX(theRect), CGRectGetMaxY(theRect));
    [thePath addQuadCurveToPoint:CGPointMake(CGRectGetMinX(theRect), CGRectGetMaxY(theRect) - theOffset) controlPoint:thePoint];
    [thePath addLineToPoint:CGPointMake(CGRectGetMinX(theRect), CGRectGetMinY(theRect) + theOffset)];
    thePoint = CGPointMake(CGRectGetMinX(theRect), CGRectGetMinY(theRect));
    [thePath addQuadCurveToPoint:CGPointMake(CGRectGetMinX(theRect) + theOffset, CGRectGetMinY(theRect)) controlPoint:thePoint];
    thePath.lineWidth = 0.5;
    [[UIColor redColor] set];
    [thePath stroke];
}

@end

I hope this helps you with your problem. I've found the factor of 1.2 for theOffset through experiments. You might modify this value if necessary. The value I have chosen for the radius is not optimal and can certainly be improved. But since it depends on the exact distance from the rim, I didn't invest much time for it.


As of iOS 13, there's an API available for this:

https://developer.apple.com/documentation/quartzcore/calayercornercurve

See CALayerCornerCurve.continuous