6

I am trying to create a custom shape NSButton. In particular I am trying to make a round button, using a custom image. I've found a tutorial on the creation of custom UIButton and tried to adapt it to NSButton. But there's a huge problem. clipsToBounds seems to be iOS only(

Here's my code:

import Cocoa

class ViewController: NSViewController {

    @IBOutlet weak var mainButton: NSButton!
    var size = 32

    override func viewDidLoad() {
        super.viewDidLoad()
        configureButton()
                // Do any additional setup after loading the view.
    }
    func configureButton()
    {
        mainButton.wantsLayer = true
        mainButton.layerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay
        mainButton.layer?.cornerRadius = 0.5 * mainButton.bounds.size.width
        mainButton.layer?.borderColor = NSColor(red:0.0/255.0, green:122.0/255.0, blue:255.0/255.0, alpha:1).CGColor as CGColorRef
        mainButton.layer?.borderWidth = 2.0
    }

    override var representedObject: AnyObject? {
        didSet {
        // Update the view, if already loaded.
        }
    }


}

What am I doing wrong? How can I make a circular NSButton? Can you suggest anything on replacing clipsToBounds?

Because here is what I was able to get so far:

enter image description here

rickster
  • 124,678
  • 26
  • 272
  • 326
Anna-Lischen
  • 856
  • 1
  • 16
  • 35
  • 1
    "clipsToBounds seems to be iOS only" But CALayer `masksToBounds` is not. The difference is merely because an NSView is not automatically layer-backed, whereas a UIView is. – matt Mar 04 '16 at 00:41

3 Answers3

8

NSButton is a subclass of NSView, so all methods in NSView, such as drawRect(_:), are also available in NSButton.

So create a new Button.swift which you draw your custom layout

import Cocoa

class Button: NSButton {

    override func drawRect(dirtyRect: NSRect) {
        super.drawRect(dirtyRect)

        // Drawing code here.
        let path = NSBezierPath(ovalIn: dirtyRect)
        NSColor.green.setFill()
        path.fill()
    }

}

enter image description here

Great Tutorial Here. It is iOS , but quite similar!

Ram Patra
  • 16,266
  • 13
  • 66
  • 81
Willjay
  • 6,381
  • 4
  • 33
  • 58
  • 1
    The code draws the circle but the remaining portion of the rect has still out there. It's because of calling the super. – selva May 25 '20 at 23:10
6

Don't play around with corner radius. A circle doesn't have corners. To make the button appear as a circle, mask the button's layer to a circle.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Even though you're on OS X, the principle is no different from this iOS answer: http://stackoverflow.com/a/16475824/341994 After all, Core Graphics is Core Graphics, and CALayer is CALayer, regardless of which platform you're on. – matt Mar 04 '16 at 00:37
  • Except of course, masking will break the focus ring, and accessibility. – Claus Jørgensen Aug 11 '16 at 13:25
  • @ClausJørgensen Very interesting point. I hadn't thought about that. – matt Aug 11 '16 at 14:41
3

You are setting the radius based upon the width of the button. By the look of your screenshot, the button is not a square when you start, so rounding the corners cannot create a circle.

Spinnaker
  • 326
  • 1
  • 12