1

I referred to some questions this , this. But couldn't get solution like I want, I am able to draw rectangle but I am not able to show only the corners of the rectangle.

I am masking rectangle to have stroke colour and fill colour, Similarly I am trying to make it to show only 4 corners.

CALayer *rectangleMaskLayer = [CALayer layer];
[self.layer addSublayer:rectangleMaskLayer];    
CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
CGMutablePathRef pathRef = CGPathCreateMutable();
CGRect dispRect = CGRectMake(10, 20, 100, 100);
shapeLayer.fillColor = [NSColor greenColor].CGColor;
shapeLayer.lineWidth = 1;
shapeLayer.strokeColor = [NSColor blackColor].CGColor;
pathRef = CGPathCreateMutable();
CGPoint startTopPoint = CGPointMake(dispRect.origin.x - 5, dispRect.origin.y);
CGPoint endTopPoint = CGPointMake(dispRect.origin.x + dispRect.size.width + 5, dispRect.origin.y);
CGRect innerRect = CGRectMake(dispRect.origin.x + 3, dispRect.origin.y + 3, dispRect.size.width - 3, dispRect.size.height - 3);
CGRect outerRect = CGRectMake(dispRect.origin.x, dispRect.origin.y, dispRect.size.width + 3, dispRect.size.height + 3);
CGPathAddRect(pathRef, NULL, outerRect);
CGPathAddRect(pathRef, NULL, innerRect);
shapeLayer.path = pathRef;
shapeLayer.fillRule = kCAFillRuleEvenOdd;
[afTrarectangleMaskLayerublayer:_trackingPositionShapeLayer];

Thank You in advance

niravdesai21
  • 4,818
  • 3
  • 22
  • 33

1 Answers1

2

Update: mistakenly did not notice required macOS, so added macOS variant. Also kept iOS variant, just in case.

macOS variant: (NSBezierPath to CGPathRef from here)

CAShapeLayer with frame macOS version

#import "ViewController.h"
#import <QuartzCore/QuartzCore.h>

@interface NSBezierPath (BezierPathQuartzUtilities)
- (CGPathRef)cgPath;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.wantsLayer = YES;

    CALayer *root = self.view.layer;
    root.backgroundColor = NSColor.blueColor.CGColor;

    CALayer *frameLayer = [self createFrameLayerWithSize:CGSizeMake(200, 200)];
    [root addSublayer:frameLayer];
    frameLayer.position = CGPointMake(CGRectGetMidX(root.bounds), CGRectGetMidY(root.bounds));
}

- (CALayer *)createFrameLayerWithSize:(CGSize)size {
    CAShapeLayer *layer = CAShapeLayer.new;
    layer.bounds = CGRectMake(0, 0, size.width, size.height);

    CGFloat kPiece = 40.0; // << can be configured
    NSBezierPath *path = NSBezierPath.new;
    [path moveToPoint:CGPointMake(0, kPiece)];
    [path lineToPoint:CGPointMake(0, 0)];
    [path lineToPoint:CGPointMake(kPiece, 0)];
    [path moveToPoint:CGPointMake(size.width - kPiece, 0)];
    [path lineToPoint:CGPointMake(size.width, 0)];
    [path lineToPoint:CGPointMake(size.width, kPiece)];
    [path moveToPoint:CGPointMake(size.width, size.height - kPiece)];
    [path lineToPoint:CGPointMake(size.width, size.height)];
    [path lineToPoint:CGPointMake(size.width - kPiece, size.height)];
    [path moveToPoint:CGPointMake(kPiece, size.height)];
    [path lineToPoint:CGPointMake(0, size.height)];
    [path lineToPoint:CGPointMake(0, size.height - kPiece)];

    layer.path = [path cgPath];
    layer.strokeColor = NSColor.whiteColor.CGColor; // << can be configured
    layer.fillColor = NSColor.clearColor.CGColor; // !! required for transparency
    layer.lineWidth = 8.0; // << can be configured
    return layer;
}

@end

@implementation NSBezierPath (BezierPathQuartzUtilities)
- (CGPathRef)cgPath
{
    NSInteger i, numElements;

    // Need to begin a path here.
    CGPathRef           immutablePath = NULL;

    // Then draw the path elements.
    numElements = [self elementCount];
    if (numElements > 0)
    {
        CGMutablePathRef    path = CGPathCreateMutable();
        NSPoint             points[3];
        BOOL                didClosePath = YES;

        for (i = 0; i < numElements; i++)
        {
            switch ([self elementAtIndex:i associatedPoints:points])
            {
                case NSMoveToBezierPathElement:
                    CGPathMoveToPoint(path, NULL, points[0].x, points[0].y);
                    break;

                case NSLineToBezierPathElement:
                    CGPathAddLineToPoint(path, NULL, points[0].x, points[0].y);
                    didClosePath = NO;
                    break;

                case NSCurveToBezierPathElement:
                    CGPathAddCurveToPoint(path, NULL, points[0].x, points[0].y,
                                        points[1].x, points[1].y,
                                        points[2].x, points[2].y);
                    didClosePath = NO;
                    break;

                case NSClosePathBezierPathElement:
                    CGPathCloseSubpath(path);
                    didClosePath = YES;
                    break;
            }
        }

        immutablePath = CGPathCreateCopy(path);
        CGPathRelease(path);
    }

    return immutablePath;
}
@end

iOS version:

Here is a demo of how to draw the corner-rect layer itself (the layout, etc. are out of scope)

CAShapeLayer for focus frame

Here is code of demo on screenshot

@interface ViewController : UIViewController
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    CALayer *root = self.view.layer;
    root.backgroundColor = UIColor.blueColor.CGColor;

    CALayer *frameLayer = [self createFrameLayerWithSize:CGSizeMake(200, 200)];
    [root addSublayer:frameLayer];
    frameLayer.position = CGPointMake(CGRectGetMidX(root.bounds), CGRectGetMidY(root.bounds));
}

- (CALayer *)createFrameLayerWithSize:(CGSize)size {
    CAShapeLayer *layer = CAShapeLayer.new;
    layer.bounds = CGRectMake(0, 0, size.width, size.height);

    CGFloat kPiece = 40.0; // << can be configured
    UIBezierPath *path = UIBezierPath.new;
    [path moveToPoint:CGPointMake(0, kPiece)];
    [path addLineToPoint:CGPointMake(0, 0)];
    [path addLineToPoint:CGPointMake(kPiece, 0)];
    [path moveToPoint:CGPointMake(size.width - kPiece, 0)];
    [path addLineToPoint:CGPointMake(size.width, 0)];
    [path addLineToPoint:CGPointMake(size.width, kPiece)];
    [path moveToPoint:CGPointMake(size.width, size.height - kPiece)];
    [path addLineToPoint:CGPointMake(size.width, size.height)];
    [path addLineToPoint:CGPointMake(size.width - kPiece, size.height)];
    [path moveToPoint:CGPointMake(kPiece, size.height)];
    [path addLineToPoint:CGPointMake(0, size.height)];
    [path addLineToPoint:CGPointMake(0, size.height - kPiece)];

    layer.path = path.CGPath;
    layer.strokeColor = UIColor.whiteColor.CGColor; // << can be configured
    layer.fillColor = UIColor.clearColor.CGColor; // !! required for transparency
    layer.lineWidth = 8.0; // << can be configured
    return layer;
}
@end
Asperi
  • 228,894
  • 20
  • 464
  • 690