3

I am trying to find a way to change the color of the selected control button. Is this possible by subclassing the NSSegmentedControl or NSSegmentedCell or any other way? If so, can someone show me the way?

memis
  • 400
  • 2
  • 9

4 Answers4

3

I did it in different way without override but just using "False color" filter. It is not perfect as it somehow change transparent of color a little bit but it is OK for me.

class RLSegmentedControl: NSSegmentedControl {
init() {
    super.init(frame: NSZeroRect)
    addFilter()
}

required init?(coder: NSCoder) {
    super.init(coder: coder)
    addFilter()
}

func addFilter() {
    let colorFilter = CIFilter(name: "CIFalseColor")!
    colorFilter.setDefaults()
    colorFilter.setValue(CIColor(cgColor: NSColor.white.cgColor), forKey: "inputColor0")
    colorFilter.setValue(CIColor(cgColor: NSColor.black.cgColor), forKey: "inputColor1")

//        colorFilter.setValue(CIColor(cgColor: NSColor.yellow.cgColor), forKey: "inputColor0")
//        colorFilter.setValue(CIColor(cgColor: NSColor.black.cgColor), forKey: "inputColor1")

    self.contentFilters = [colorFilter]
}
}

enter image description here

brianLikeApple
  • 4,262
  • 1
  • 27
  • 46
1

You can subclass NSSegmentedCell e override the drawSegment method:

override func drawSegment(_ segment: Int, inFrame frame: NSRect, with controlView: NSView) {
    var color: NSColor
    if selectedSegment == segment {
        color = NSColor.red
    } else {
        color = NSColor.white
    }
    color.setFill()
    frame.fill()
    super.drawSegment(segment, inFrame: frame, with: controlView)
}
Edson Guido
  • 43
  • 1
  • 10
  • Works on some segment cells, but half of the cells in my case the frame is only half the width it should be (the entire cell is *not* getting filled). – wcochran Oct 23 '19 at 23:48
0

You need to subclass NSSegmentedCell and overwrite the following method:

- (NSColor *)highlightColorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView

From the documentation:

Returns the color the receiver uses when drawing the selection highlight.

You should not assume that a cell would necessarily want to draw itself with the value returned from selectedControlColor. A cell may wish to draw with different a selection highlight color depending on such things as the key state of its controlView.

Community
  • 1
  • 1
floschliep
  • 513
  • 5
  • 14
  • I have tried this before. This NSCell method is never called in NSSegmentedCell something which is stated and in the documentation _"You should not assume that a cell would necessarily want to draw itself with the value returned from selectedControlColor. A cell may wish to draw with different a selection highlight color depending on such things as the key state of its controlView."_ – memis May 19 '17 at 08:28
  • I would file a bug report for this. The documentation says that you can use this method to alter the highlight color, but doesn't say anything about it not being used. The only solution seems to be overriding -drawInteriorWithFrame:inView: and handling all the drawing yourself. – floschliep May 19 '17 at 09:57
  • Not seeing this method in the docs: https://developer.apple.com/documentation/appkit/nssegmentedcell – wcochran Oct 23 '19 at 22:03
  • @wcochran It's a method of NSCell, which is the superclass of the superclass of NSSegmentedCell: https://developer.apple.com/documentation/appkit/nscell/1534018-highlightcolorwithframe?language=objc – floschliep Oct 27 '19 at 13:45
0

When using macOS 12.2.2 or newer, you can use the new property selectedSegmentBezelColor, with 'appearances that support it' according the documentation of Apple. Style 'Rounded' for example seems to work, while 'Textured Rounded' not.

segmentedControl.selectedSegmentBezelColor = .systemOrange
Ely
  • 8,259
  • 1
  • 54
  • 67