Reputation: 7204
I am trying to produce a custom header for my NSTableView. I would like to change the font of the header text and remove the borders and vertical separators.
My current top and bottom header is shown below:
Does anyone know how do I do this please?
UPDATE: After applying the fix the header now looks as I intended:
Upvotes: 4
Views: 3309
Reputation: 56
What seems to work in macOS 11:
Set NSTableHeaderCell background
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
tableColumn?.headerCell.drawsBackground = true
tableColumn?.headerCell.backgroundColor = .orange
...
Set NSTableView style in IB to Full Width
Upvotes: 0
Reputation: 1030
The above answers works also directly you can use in viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableColumns.forEach { (column) in
column.headerCell.backgroundColor = NSColor.white
column.headerCell.drawsBackground = true
column.headerCell.isBordered = false
column.headerCell.attributedStringValue = NSAttributedString(string: column.title, attributes: [NSAttributedString.Key.font: NSFont.systemFont(ofSize: 13)])
}
}
Upvotes: 2
Reputation: 10355
You will need to take over the drawing yourself by subclassing NSTableHeaderCell
, like so:
final class CustomTableHeaderCell : NSTableHeaderCell {
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(textCell: String) {
super.init(textCell: textCell)
self.font = NSFont.boldSystemFontOfSize(20)
}
override func drawWithFrame(cellFrame: NSRect, inView controlView: NSView) {
// skip super.drawWithFrame(), since that is what draws borders
self.drawInteriorWithFrame(cellFrame, inView: controlView)
}
override func drawInteriorWithFrame(cellFrame: NSRect, inView controlView: NSView) {
let titleRect = self.titleRectForBounds(cellFrame)
self.attributedStringValue.drawInRect(titleRect)
}
}
If you are setting up the table programmatically, you would do it like:
let col = NSTableColumn(identifier: id)
col.headerCell = CustomTableHeaderCell(textCell: title)
col.title = title
self.dataTableView.addTableColumn(col)
Otherwise, you should be able to just set the name of your class to your subclass' name in Interface Builder.
Upvotes: 1
Reputation: 7204
Actually both the answers from mprudhom and Pronto contributed nicely to the final fix. Many thanks to both of you.
I thought I'd post my final answer so anyone following on can see how I fixed it.
I couldn't use mprudhom's code alone as my table only had a NSTableHeaderView and no TableHeaderCells. Fortunately Pronto came to the rescue on that:
class MyTable: NSTableView, NSTableViewDataSource, NSTableViewDelegate
{
override func tableView(tableView: NSTableView, viewForTableColumn tableColumn: NSTableColumn?, row: Int) -> NSView?
{
tableColumn!.headerCell = MyTableHeaderCell(textCell: tableColumn!.identifier)
}
}
I used the NSTableHeaderCell code directly from mprudhom:
final class MyTableHeaderCell : NSTableHeaderCell
{
required init?(coder aDecoder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}
override init(textCell: String)
{
super.init(textCell: textCell)
self.font = NSFont.boldSystemFontOfSize(14)
}
override func drawWithFrame(cellFrame: NSRect, inView controlView: NSView)
{
//super.drawWithFrame(cellFrame, inView: controlView)//, since that is what draws borders
self.drawInteriorWithFrame(cellFrame, inView: controlView)
}
override func drawInteriorWithFrame(cellFrame: NSRect, inView controlView: NSView)
{
let titleRect = self.titleRectForBounds(cellFrame)
self.attributedStringValue.drawInRect(titleRect)
}
}
Once these two methods were implemented, I had one last problem in that the NSTableHeaderView was drawn without the border as required but did have a grey background. So I overrode the NSTableHeaderView class with this method:
class ForecastHeaderView : NSTableHeaderView
{
required init?(coder: NSCoder)
{
super.init(coder: coder)
}
override init(frame frameRect: NSRect)
{
super.init(frame: frameRect)
self.wantsLayer = true
}
override func drawLayer(layer: CALayer, inContext ctx: CGContext)
{
super.drawLayer(layer, inContext: ctx)
layer.backgroundColor = CGColorCreateGenericGray(1.0, 1.0)
}
}
Upvotes: 6
Reputation: 1681
One way to do it, in your NSTableViewDelegate's
viewForTableColumn
-function:
if tableColumn!.identifier == "description" {
let cell = NSTableHeaderCell()
cell.title = "New Title"
cell.backgroundColor = NSColor.redColor()
cell.drawsBackground = true
cell.bordered = false
cell.font = NSFont(name: "Helvetica", size: 16)
tableColumn!.headerCell = cell
}
Upvotes: 3