Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a custom themed NSButton without subclassing NSButtonCell?

Tags:

I am currently working on a custom themed NSButton. Every tutorial, or guide I have found requires to subclass NSButtonCell, even the guide from Apple.

All of those seem to be outdated, because all cell methods in NSControl are deprecated in Yosemite. I have not found any recommendations or guides what to use as a substitute.

This is the only statement, I could find:

Gradual deprecation of NSCell

Mac OS X 10.10 takes another step towards the eventual deprecation of cells. Direct access to the cell of a control is discouraged, and methods which allow it will be formally deprecated in a subsequent release. A variety of cell-level APIs have been promoted to various Control subclasses in order to provide cell-free access to important functionality. NSLevelIndicator, NSTextField, NSSearchField, NSSlider, and NSPathControl all have new properties for this purpose. Cell-based NSTableViews are now deprecated, and view-based NSTableViews should be used instead. Matrix-based NSBrowsers are also deprecated in favor of the item-based interface.

Excerpt from: AppKit Release Notes for OS X v10.10

No words on NSButton though.

NSTextField supports layer backed views; because of that, I tried the same approach on my NSButton, but that has no effect.

var btn = NSButton(NSMakeRect(0, 0, 50, 20))
btn.wantsLayer = true
btn.bordered = false
btn.layer?.backgroundColor = NSColor(calibratedWhite: 0.99, alpha: 1).CGColor
btn.layer?.borderWidth = 1
btn.layer?.borderColor = NSColor(calibratedWhite: 0.81, alpha: 1).CGColor
like image 883
Afterlame Avatar asked Feb 24 '15 16:02

Afterlame


1 Answers

I would definitely spend more time looking into the layer-backed view approach. I'm not sure why it didn't work for you because there's no reason for layers not to work on an NSButton (effectively an NSView derivative).

Also weighing on looking more into layers is your mentioning of animation.

Some code extracted from a project I am working on (custom NSButton):

From init()...

    self.wantsLayer = true
    self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay

    self.layer?.borderColor = NSColor.gridColor().CGColor
    self.layer?.borderWidth = 0.5
    self.layer?.backgroundColor = NSColor.whiteColor().CGColor

You can then get fine-grained control in the display cycle specific to layers with:

override var wantsUpdateLayer:Bool{
    return true
}

override func updateLayer() {
    // your code here
    super.updateLayer()
}

If your custom button needs a shape then you can even use a CAShapeLayer below to make your backing layer a special shape...more detail to be looked into.

override func makeBackingLayer() -> CALayer {
    return CAShapeLayer()
}
like image 135
Sam Avatar answered Sep 21 '22 06:09

Sam