How to create a custom themed NSButton without subclassing NSButtonCell?
cocoa, macos, swift
Solution
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()
}
Problem
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 ```