I have a swift program that displays a custom table. Originally I incorrectly used a NSTextField for each cell and ran into a formatting issue. As can be seen in the picture below, the text in each cell is up against the top border. I was unable to figure out how to solve the problem so I posted my original code below. A response suggested that I change the NSTextField to a NSTableCellView. So I changed my code (new code is now below) to incorporate the NSTableCellView. Unfortunately, I ended up with the same formatting problem. I thought I could apply a constraint to the NSTableCellView relative to its parent but with no success (attempt commented out in delegate). It would be appreciated if someone could point me in the right direction to solve this issue. If I need to post more of my code, please let me know.
// Coordinators delegate
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let dataCell = CustomTableCellView()
switch tableColumn?.identifier.rawValue {
case "fund":
dataCell.Setup(rectWidth: 100.0, row: row, column: tableColumn!, numberOfRows: closingValues.count)
dataCell.textField?.stringValue = closingValues[row].fundName
case "date":
dataCell.Setup(rectWidth: 120.0, row: row, column: tableColumn!, numberOfRows: closingValues.count)
dataCell.textField?.stringValue = SQLDateFormatter.string(from: closingValues[row].timeStamp)
default:
dataCell.Setup(rectWidth: 100.0, row: row, column: tableColumn!, numberOfRows: closingValues.count)
dataCell.textField?.stringValue = String(format: "$%.2f", closingValues[row].close)
}
// let constraints = [
// dataCell.topAnchor.constraint(equalTo: ??parent??.topAnchor, constant: 5.0)
// ]
// NSLayoutConstraint.activate(constraints)
return dataCell
}
// Custom NSTableCellView
class CustomTableCellView: NSTableCellView {
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
}
func Setup(rectWidth: CGFloat, row: Int, column: NSTableColumn, numberOfRows: Int) {
self.autoresizingMask = .width
let nsRectangle: NSRect = NSMakeRect(0, 0, rectWidth, 24)
let customTextField: CustomTextField = CustomTextField(frame: nsRectangle)
customTextField.SetTextAttributes(row: row, column: column, numberOfRows: numberOfRows)
self.textField = customTextField
self.addSubview(customTextField)
}
required init?(coder decoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
After some more thought, I realized all I needed to do is get access to the base line offset of the cell text. So I made 2 changes to my CustomTextField class (the code for which is included below). 1) Commented out all text attributes from the SetTextAttributes function. 2) Added all the code above super.draw(dirtyRect) in the override func draw(_ dirtyRect: NSRect). By going to an attributed string value I got access to the base line offset. This allowed me to move the text down vertically. Problem solved.
class CustomTextField :NSTextField {
var row: Int = 0
var column: NSTableColumn = NSTableColumn()
var numberOfRows: Int = 0
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
func SetTextAttributes(row: Int, column: NSTableColumn, numberOfRows: Int) {
// textColor = .blue
// backgroundColor = .white
// isBordered = false
// isEditable = false
// font = NSFont(name: "Arial", size: 16)!
// alignment = .center
self.row = row
self.column = column
self.numberOfRows = numberOfRows
}
override func draw(_ dirtyRect: NSRect) {
isBordered = false
isEditable = false
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
attributedStringValue = NSAttributedString(string: stringValue, attributes:
[NSAttributedString.Key.foregroundColor: NSColor.blue,
NSAttributedString.Key.backgroundColor: NSColor.white,
NSAttributedString.Key.font: NSFont(name: "Arial", size: 16)!,
NSAttributedString.Key.paragraphStyle: paragraphStyle,
NSAttributedString.Key.baselineOffset: -4.0
])
super.draw(dirtyRect)
NSColor.lightGray.set()
let customBorder = NSBezierPath()
customBorder.move(to: NSMakePoint(0.0, dirtyRect.height))
customBorder.line(to: NSMakePoint(0.0, 0.0))
customBorder.line(to: NSMakePoint(dirtyRect.width, 0.0))
if column.title == "Closing" {
customBorder.line(to: NSMakePoint(dirtyRect.width, dirtyRect.height))
}
if row == numberOfRows - 1 {
if column.title == "Fund" || column.title == "Date" {
customBorder.move(to: NSMakePoint(dirtyRect.width, dirtyRect.height))
customBorder.line(to: NSMakePoint(0.0, dirtyRect.height))
}
customBorder.line(to: NSMakePoint(0.0, dirtyRect.height))
}
customBorder.lineWidth = 2
customBorder.stroke()
}
}