1

MacOS 10.12+, Xcode 8+, Swift 3:

I'd like to programmatically customize the font and drawing of an NSTableView header. I know there are older questions about this, but I couldn't find anything that works today.

For example, I tried to subclass NSTableHeaderCell to set a custom font:

class MyHeaderCell: NSTableHeaderCell {
    override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
        NSLog("MyHeaderCell is drawing")
        font = NSFont.boldSystemFont(ofSize: 12)
        super.drawInterior(withFrame: cellFrame, in: controlView)
    }
}

And then use that subclass in my table view:

tableColumn.headerCell = MyHeaderCell()

I see the message "MyHeaderCell is drawing" in the console, but the font of the table header doesn't change.

sam
  • 3,399
  • 4
  • 36
  • 51
  • 1
    Did you try setting `attributedStringValue`? – Willeke Sep 16 '16 at 16:42
  • @Willeke Yes, I tried setting attributedStringValue. My setting were ignored. – sam Sep 16 '16 at 17:58
  • 1
    @sam In my implementation of MyHeaderCell using `attributedStringValue` works perfectly! So I guess there is something wrong with your code. You may find some hints [here](http://stackoverflow.com/questions/32666795/how-do-i-override-layout-of-nstableheaderview) – Heinrich Giesen Sep 17 '16 at 10:43
  • @HeinrichGiesen, Willeke: It does work when I assign attributedStringValue inside my drawInterior() override. I had set the attributedStringValue property on the headerCell before and that setting was ignored. Thanks to both of you. – sam Sep 17 '16 at 21:22

2 Answers2

5

Thanks to comments from @HeinrichGiesen and @Willeke, I got it working. I'm posting it here in case it helps someone down the line. Note that my way of customizing the background color isn't that flexible. I'm really just tinting the default drawing. It's good enough for my purposes.

final class MyHeaderCell: NSTableHeaderCell {

    // Customize background tint for header cell
    override func draw(withFrame cellFrame: NSRect, in controlView: NSView) {
        super.draw(withFrame: cellFrame, in: controlView)
        NSColor(red: 0.9, green: 0.9, blue: 0.8, alpha: 0.2).set()
        NSRectFillUsingOperation(cellFrame, .sourceOver)
    }

    // Customize text style/positioning for header cell
    override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
        attributedStringValue = NSAttributedString(string: stringValue, attributes: [
            NSFontAttributeName: NSFont.systemFont(ofSize: 11, weight: NSFontWeightSemibold),
            NSForegroundColorAttributeName: NSColor(white: 0.4, alpha: 1),
        ])
        let offsetFrame = NSOffsetRect(drawingRect(forBounds: cellFrame), 4, 0)
        super.drawInterior(withFrame: offsetFrame, in: controlView)
    }
}
sam
  • 3,399
  • 4
  • 36
  • 51
-1

It has been some time since anyone has addressed this question. I've encountered the same very frustrating problem using Swift 5 and Xcode 12. Here is what I have learned using an nstableview approach that does not require subclassing.

  1. at the beginning of the func tableView(_ myTable: NSTableView... add the following lines of code:

     tableColumn?.headerCell.drawsBackground = true
     tableColumn?.headerCell.backgroundColor = fill1Tint 
    

This code changes the headerCell background color (and fill1Tint is some NSColor).

Then add:

    let paragraphStyle: NSMutableParagraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = NSTextAlignment.center
  1. within each tableColumn.identifier block, add an attributed text string such as:

         let title: String = "Value"
         tableColumn?.headerCell.attributedStringValue = NSAttributedString(string: title, attributes: [
             NSAttributedString.Key.font: fontMedium,
             NSAttributedString.Key.foregroundColor: text1Tint,
             NSAttributedString.Key.paragraphStyle : paragraphStyle])
    

This code enables both a different background and centered, attributed text.

RFAustin
  • 315
  • 2
  • 9
  • Most `NSTableVIewDataSource` and `NSTableViewDelegate` methods start with `func tableView(_ tableView: NSTableView,`. Which method is `func tableView(_ myTable: NSTableView...`? – Willeke Dec 08 '21 at 10:49
  • func tableView(_ myTable: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? … and the key is within each tableColumn.identifier block... – RFAustin May 04 '22 at 19:44