How do I override layout of NSTableHeaderView?

前端 未结 4 1807
说谎
说谎 2021-01-06 06:30

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 curr

相关标签:
4条回答
  • 2021-01-06 07:04

    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
    }
    
    0 讨论(0)
  • 2021-01-06 07:04

    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)])
                  }
    }
    
    0 讨论(0)
  • 2021-01-06 07:07

    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.

    0 讨论(0)
  • 2021-01-06 07:19

    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)
        }
    }
    
    0 讨论(0)
提交回复
热议问题