Search code examples
swiftmacosnsbutton

Disable NSButton highlight and stop image from changing when pressed


Inside my new MacOS app I use a NSButton with an image. Whenever I press the button and hold it, the current image will become darker/highlighted, until I release the button again. I don't want this behaviour, but really can't figure out how to disable it. Current Button settings:

enter image description here

The main answer on this old post explains a way to do it by changing the button type to MomentaryChange, but this no longer seems to work.

If it is possible I would like to disable it in the storyboard itself, but if I that's not possible I am okay with using code for it.


Solution

  • After a couple of hours of messing around with NSButton I finally figured out how to get control over its pressed state. The NSButton itself doesn't offer any way to control it, but the underlying NSButtonCell does. To set the image for the pressed state:

    (self.myButton.cell! as! NSButtonCell).alternateImage = NSImage(named: "myImage")
    

    You are also able to define the way the button shows its different state by using the highlightsBy (highlighted means pressed) and showsStateBy (states are normally used with check buttons, which have an on and off state flag). Aside from all the predefined states NSContentsCellMask, NSPushInCellMask, NSChangeGrayCellMask, and NSChangeBackgroundCellMask you can also set them to 0 to disable different drawing. I found this old Github post explaining it in further detail.

    So to disable the different appearance when pressed/highlighted:

    (self.timerButton.cell! as! NSButtonCell).highlightsBy = NSCell.StyleMask(rawValue: 0)
    

    I also found a way to disabled the highlighted state itself, which may be useful when you have many buttons. You can override the draw(_ dirtyRect: NSRect) function either in a custom NSButton class or in a general extension to keep the -highlighted flag on false:

    extension NSButton {
        override open func draw(_ dirtyRect: NSRect) {
            self.highlight(false)
            super.draw(dirtyRect)
        }
    }