How do I modify height of tableview header cell background color

I have code that displays an NSTableView. I have the functionality I want but am having problems with the formatting. In the makeNSView function I can set the header cell text, background color and alignment. What I have been unable to determine is how to add what I would term padding to the header cell background color such that it is taller, i.e. extends further above and below the text. As a secondary issue, I would like to be able to control the border widths of the table cells i.e. the NSViews, such that they appear all the same. Right now, adjacent cell edges have double width borders and non adjacent cell edges have single width borders. Below are the displayed results and code.

struct BetterTableView: NSViewRepresentable {
    
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }

    class Coordinator: NSObject, NSTableViewDelegate, NSTableViewDataSource {
        
        var dateSorting: String = "ASC"
        var closingSorting: String = "ASC"
        var closingValues: [ClosingValue] = []
        
        override init() {
            super.init()
            self.closingValues = GetValues()
        }

        func tableView(_ tableView: NSTableView, mouseDownInHeaderOf tableColumn: NSTableColumn) {
            
            switch tableColumn.title {
            case "Date":
                if dateSorting == "ASC" {
                    closingValues.sort {
                        $0.date > $1.date
                    }
                    dateSorting = "DESC"
                } else {
                    closingValues.sort {
                        $0.date < $1.date
                    }
                    dateSorting = "ASC"
                }
            case "Closing":
                if closingSorting == "ASC" {
                    closingValues.sort {
                        $0.date > $1.date
                    }
                    closingSorting = "DESC"
                } else {
                    closingValues.sort {
                        $0.date < $1.date
                    }
                    closingSorting = "ASC"
                }
            default:
                print("default")
            }
            tableView.reloadData()
            tableView.scrollRowToVisible(0)
        }
        
        func numberOfRows(in tableView: NSTableView) -> Int {
            closingValues.count
        }
        
        func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
            var nsView = NSView()
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.alignment = .center
            let attributes1: [NSAttributedString.Key: Any] = [
                .foregroundColor: NSColor.blue,
                .paragraphStyle: paragraphStyle,
                .font: NSFont(name: "Arial", size: 14.0) as Any
            ]
            var attributedString = NSAttributedString()
            let tempNSView = NSTextField()
            switch tableColumn {
            case tableView.tableColumns[0]:
                attributedString = NSAttributedString(string: closingValues[row].name, attributes: attributes1)
            case tableView.tableColumns[1]:
                attributedString = NSAttributedString(string: closingValues[row].date, attributes: attributes1)
            case tableView.tableColumns[2]:
                let closeAsString = String(format: "$%.2f", closingValues[row].close)
                attributedString = NSAttributedString(string: closeAsString, attributes: attributes1)
            default:
                print("problem in table view switch statement")
            }
            tempNSView.backgroundColor = NSColor.white
            tempNSView.isBordered = true
            tempNSView.isEditable = false
            tempNSView.attributedStringValue = attributedString
            nsView = tempNSView
            return nsView
        }
        
    } // end of coordinator class
    
    func makeNSView(context: Context) -> NSScrollView {
        
        let tableView = NSTableView()
        
        tableView.style = .plain
        tableView.delegate = context.coordinator
        tableView.dataSource = context.coordinator
        tableView.addTableColumn(NSTableColumn())
        tableView.addTableColumn(NSTableColumn())
        tableView.addTableColumn(NSTableColumn())
        tableView.intercellSpacing = NSSize(width: 0.0, height: 0.0)

        tableView.headerView?.frame.size.height = 20.0

        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = .center
        
        let attributes: [NSAttributedString.Key: Any] = [
            .foregroundColor: NSColor.black,
            .paragraphStyle: paragraphStyle,
            .font: NSFont.systemFont(ofSize: 18)
        ]
        
        let column0AttributedString = NSAttributedString(string: "Stock", attributes: attributes)
        let column0Header = tableView.tableColumns[0]
        column0Header.headerCell.drawsBackground = true
        column0Header.headerCell.backgroundColor = NSColor.systemMint
        column0Header.headerCell.alignment = .center
        column0Header.headerCell.attributedStringValue = column0AttributedString
        column0Header.sizeToFit()
        column0Header.minWidth = 90.0
        column0Header.maxWidth = 90.0
        
        let column1AttributedString = NSAttributedString(string: "Date", attributes: attributes)
        let column1Header = tableView.tableColumns[1]
        column1Header.headerCell.drawsBackground = true
        column1Header.headerCell.backgroundColor = NSColor.systemMint
        column1Header.headerCell.alignment = .center
        column1Header.headerCell.attributedStringValue = column1AttributedString
        column1Header.sizeToFit()
        column1Header.minWidth = 125.0
        column1Header.maxWidth = 125.0
        
        let column2AttributedString = NSAttributedString(string: "Closing", attributes: attributes)
        let column2Header = tableView.tableColumns[2]
        column2Header.headerCell.drawsBackground = true
        column2Header.headerCell.backgroundColor = NSColor.systemMint
        column2Header.headerCell.alignment = .center
        column2Header.headerCell.attributedStringValue = column2AttributedString
        column2Header.sizeToFit()
        column2Header.minWidth = 90.0
        column2Header.maxWidth = 90.0
        
        let scrollView = NSScrollView()
        scrollView.documentView = tableView
        
        return scrollView
    }
    
    func updateNSView(_ nsView: NSScrollView, context: Context) {
        let tableView = (nsView.documentView as! NSTableView)
        print("in update ns view")
        // work on this section
    }
}

Accepted Reply

The solution is to create a subclass of NSTableHeaderCell. In the subclass you override several functions and insert customizations as desired in the drawInterior function. Below is the call to and subclass created.

// in func makeNSView
        let customHeaderCell0 = CustomHeaderCell()
        customHeaderCell0.stringValue = "Stock"
        let column0Header = tableView.tableColumns[0]
        column0Header.minWidth = 90.0
        column0Header.headerCell = customHeaderCell0

// subclass
final class CustomHeaderCell: NSTableHeaderCell {
    
    override init(textCell: String) {
        super.init(textCell: textCell)
    }
    required init(coder: NSCoder) {
        fatalError("init(coder:) not implemented")
    }
    override func draw(withFrame cellFrame: NSRect, in controlView: NSView) {
        self.drawInterior(withFrame: cellFrame, in: controlView)
    }
    override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
        let rect = NSRect(x: cellFrame.origin.x, y: cellFrame.origin.y, width: cellFrame.size.width, height: cellFrame.size.height)
        NSColor.systemMint.set()
        NSBezierPath(rect: rect).fill()
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = .center
        let headerCellText = NSAttributedString(string: stringValue, attributes:
                                                    [NSAttributedString.Key.foregroundColor: NSColor.black,
                                                     NSAttributedString.Key.font: NSFont(name: "Arial", size: 18)!,
                                                     NSAttributedString.Key.paragraphStyle: paragraphStyle,
                                                     NSAttributedString.Key.baselineOffset: -6.0
                                                    ])
        headerCellText.draw(in: cellFrame)
    }
}

Replies

The solution is to create a subclass of NSTableHeaderCell. In the subclass you override several functions and insert customizations as desired in the drawInterior function. Below is the call to and subclass created.

// in func makeNSView
        let customHeaderCell0 = CustomHeaderCell()
        customHeaderCell0.stringValue = "Stock"
        let column0Header = tableView.tableColumns[0]
        column0Header.minWidth = 90.0
        column0Header.headerCell = customHeaderCell0

// subclass
final class CustomHeaderCell: NSTableHeaderCell {
    
    override init(textCell: String) {
        super.init(textCell: textCell)
    }
    required init(coder: NSCoder) {
        fatalError("init(coder:) not implemented")
    }
    override func draw(withFrame cellFrame: NSRect, in controlView: NSView) {
        self.drawInterior(withFrame: cellFrame, in: controlView)
    }
    override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
        let rect = NSRect(x: cellFrame.origin.x, y: cellFrame.origin.y, width: cellFrame.size.width, height: cellFrame.size.height)
        NSColor.systemMint.set()
        NSBezierPath(rect: rect).fill()
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = .center
        let headerCellText = NSAttributedString(string: stringValue, attributes:
                                                    [NSAttributedString.Key.foregroundColor: NSColor.black,
                                                     NSAttributedString.Key.font: NSFont(name: "Arial", size: 18)!,
                                                     NSAttributedString.Key.paragraphStyle: paragraphStyle,
                                                     NSAttributedString.Key.baselineOffset: -6.0
                                                    ])
        headerCellText.draw(in: cellFrame)
    }
}