In my case the task was to have 0.5 pt (1 px on Retina display) separator. Seems even when intercellSpacing
set to .zero
(or 0.5 pt in my case) AppKit still preserving 1 pt space between rows when drawing selection.
I ended up by subclassing NSTableRowView
. With custom row I can set separator to any height. Here is a Swift 4.2 example:
class WelcomeRecentDocumentsView: View {
private lazy var tableView = TableView().autolayoutView()
private lazy var scrollView = ScrollView(tableView: tableView).autolayoutView()
override var intrinsicContentSize: NSSize {
return CGSize(width: 240, height: 400)
}
private var recentDocumentsURLs = (0 ..< 10).map { $0 }
}
extension WelcomeRecentDocumentsView: NSTableViewDataSource {
func numberOfRows(in tableView: NSTableView) -> Int {
return recentDocumentsURLs.count
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
return tableView.makeView(ItemView.self)
}
}
extension WelcomeRecentDocumentsView: NSTableViewDelegate {
func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
// Returning custom RowView.
return RowView(separatorHeight: separatorHeight, separatorColor: tableView.gridColor)
}
}
extension WelcomeRecentDocumentsView {
private var separatorHeight: CGFloat {
return convertFromBacking(1)
}
override func setupUI() {
addSubview(scrollView)
let column = NSTableColumn(identifier: "com.example.column", resizingMask: .autoresizingMask)
tableView.addTableColumn(column)
tableView.columnAutoresizingStyle = .uniformColumnAutoresizingStyle
tableView.headerView = nil
tableView.setAutomaticRowHeight(estimatedHeight: ItemView.defaultHeight)
tableView.intercellSpacing = CGSize(height: separatorHeight)
tableView.gridStyleMask = .solidHorizontalGridLineMask
}
override func setupHandlers() {
tableView.delegate = self
tableView.dataSource = self
}
override func setupLayout() {
LayoutConstraint.pin(to: .bounds, scrollView).activate()
}
override func setupDefaults() {
tableView.sizeLastColumnToFit()
}
}
extension WelcomeRecentDocumentsView {
class RowView: NSTableRowView {
let separatorHeight: CGFloat
let separatorColor: NSColor
init(separatorHeight: CGFloat = 1, separatorColor: NSColor = .gridColor) {
self.separatorHeight = separatorHeight
self.separatorColor = separatorColor
super.init(frame: .zero)
}
required init?(coder decoder: NSCoder) {
fatalError()
}
override func drawSelection(in dirtyRect: NSRect) {
let rect = bounds.insetBottom(by: -separatorHeight)
NSColor.alternateSelectedControlColor.setFill()
rect.fill()
}
override func drawSeparator(in dirtyRect: NSRect) {
let rect = bounds.insetTop(by: bounds.height - separatorHeight)
separatorColor.setFill()
rect.fill()
}
}
class ItemView: View {
static let defaultHeight: CGFloat = 52
override var intrinsicContentSize: NSSize {
return CGSize(intrinsicHeight: type(of: self).defaultHeight)
}
}
}
NSZeroSize
! – Grainy