3

There are several ways to four draw rounded corners in Cocoa, either using CALayer or NSBezierPath. But how can I draw a single rounded corner on a NSButton?

The current structure of the button is:

NSButton *button = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 50, 20)];
[button setTitle:@"My button"];
[button.cell setBackgroundColor:[NSColor grayColor]];

What I want to do is have a rounded top-right corner with a radius of 10. How do I do that?

Christoffer
  • 25,035
  • 18
  • 53
  • 77

3 Answers3

4

SOLUTION:

Override drawRect:

CGFloat cornerRadius = 10;

NSBezierPath *path = [NSBezierPath bezierPath];

// Start drawing from upper left corner
[path moveToPoint:NSMakePoint(NSMinX(self.bounds), NSMinY(self.bounds))];

// Draw top border and a top-right rounded corner
NSPoint topRightCorner = NSMakePoint(NSMaxX(self.bounds), NSMinY(self.bounds));
[path lineToPoint:NSMakePoint(NSMaxX(self.bounds) - cornerRadius, NSMinY(self.bounds))];
[path curveToPoint:NSMakePoint(NSMaxX(self.bounds), NSMinY(self.bounds) + cornerRadius)
     controlPoint1:topRightCorner
     controlPoint2:topRightCorner];

// Draw right border, bottom border and left border
[path lineToPoint:NSMakePoint(NSMaxX(self.bounds), NSMaxY(self.bounds))];
[path lineToPoint:NSMakePoint(NSMinX(self.bounds), NSMaxY(self.bounds))];
[path lineToPoint:NSMakePoint(NSMinX(self.bounds), NSMinY(self.bounds))];

// Fill path
[[NSColor whiteColor] setFill];
[path fill];
Christoffer
  • 25,035
  • 18
  • 53
  • 77
2

You need to use NSBezierPath and draw a custom button as per your requirement.

You need to work something like this :

NSBezierPath *path = [NSBezierPath bezierPath];
[path setLineWidth:1];
[path moveToPoint:NSMakePoint(0, 0)];

[path curveToPoint:NSMakePoint(width * 0.1, height)
     controlPoint1:NSMakePoint(width * 0.05, height)
     controlPoint2:NSMakePoint(width * 0.03, height * 0.05)];

And so on... Untill you make a closed button area and you get exact shape.

Anoop Vaidya
  • 46,283
  • 15
  • 111
  • 140
2

Based on Christoffer Christoffer's approach, I've created a more general solution where you can choose which corner you want to round. It's in Swift 3 and also works on both macOS & iOS/tvOS.

You can find the Swift Playground here: https://github.com/janheiermann/BezierPath-Corners

Community
  • 1
  • 1
JanApotheker
  • 1,746
  • 1
  • 17
  • 23
  • Tried to use this code on a mac project, but unfortunately it is not working !!!, the rounds are not correct, ie, BezierPath.init(rect: rect, roundedCorners: [.topLeft, .bottomRight], cornerRadius: 8.0) does not look at all as intended. – Klajd Deda Apr 09 '18 at 16:33
  • This project uses the control points wrong, that's why the corners are not round. –  Sep 01 '20 at 08:18
  • The project is using curve(to:...) rather than appendArc(withCenter:…). That's why it's not what you'd expect. – danwood Apr 07 '21 at 21:48