I have an NSTableView whose first row is pushed down 10 pt from the top. Headers are turned off, there are no group rows, cell spacing is 0, and the enclosing scroll view's content inset is 0.
UPDATED
Here's a sample project that demonstrates the issue.
Here's a grab of the view hierarchy debugger:
Here's the vertical constraints of the first row's NSTableRowView
while paused in the view hierarchy debugger:
I tried implementing the delegate's tableView(_:didAdd:forRow:) and inspecting the constraints, first with constraintsAffectingLayout(for:):
[<NSLayoutConstraint:0x60000390bd40 'NSTableRowView_Encapsulated_Layout_Height' NSTableRowView:0x7fdb12e26eb0.height == 24 priority:500 (active)>]
Then printing all the row view's constraints:
- 0 : <NSLayoutConstraint:0x60000390bcf0 'NSTableRowView_Encapsulated_Layout_Width' NSTableRowView:0x7fdb12e26eb0.width == 329 priority:500 (active)>
- 1 : <NSLayoutConstraint:0x60000390bd40 'NSTableRowView_Encapsulated_Layout_Height' NSTableRowView:0x7fdb12e26eb0.height == 24 priority:500 (active)>
- 2 : <NSAutoresizingMaskLayoutConstraint:0x60000390bbb0 h=--& v=-&- InlineCell.minX == 16 (active, names: InlineCell:0x7fdb12e283a0, '|':NSTableRowView:0x7fdb12e26eb0 )>
- 3 : <NSAutoresizingMaskLayoutConstraint:0x60000390bc00 h=--& v=-&- InlineCell.width == 297 (active, names: InlineCell:0x7fdb12e283a0 )>
- 4 : <NSAutoresizingMaskLayoutConstraint:0x60000390bc50 h=--& v=-&- InlineCell.minY == 0 (active, names: InlineCell:0x7fdb12e283a0, '|':NSTableRowView:0x7fdb12e26eb0 )>
- 5 : <NSAutoresizingMaskLayoutConstraint:0x60000390bca0 h=--& v=-&- V:[InlineCell]-(0)-| (active, names: InlineCell:0x7fdb12e283a0, '|':NSTableRowView:0x7fdb12e26eb0 )>
The cell's minY
constraint is set to 0, but the row is using an autoresizing mask. The table uses a simple diffable datasource:
NSTableViewDiffableDataSourceReference(tableView: table) { tableView, column, row, item in
guard let cell = tableView.makeView(withIdentifier: inlineCellIdentifier, owner: self) as? NSTableCellView else {
preconditionFailure("Failed to create results cell")
}
cell.textField?.textColor = self.themeAttributes.color
cell.textField?.font = self.themeAttributes.font
cell.textField?.stringValue = self.displayString(for: item)
return cell
}
The only delegate method implemented is tableView(_:heightOfRow:). The table aligns itself with the lines of a sibling text view so it gets it row height from there:
func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
guard let layoutManager = editor?.layoutManager else {
preconditionFailure("Missing layout manager in editor")
}
return height(of: row, in: layoutManager)
}
This seems like it's probably obvious, but I don't see why the table is forcing its rows to be offset like this. I've found plenty of questions on this forum asking how to insert a gap at the top of the table, but not how to remove one. Any advice?
It's not a bug, as stated in some comments, it's a new way how the NSTableView
works in Big Sur (actually there's a bug, but elsewhere, see below). Free Pascal site contains nice overview of what's new.
NSTableView
propertiesmacOS Big Sur introduced new NSTableView
properties:
style
effectiveStyle
style
documentation:
The default value for this property is
NSTableView.Style.automatic
in macOS 11. Apps that link to previous macOS versions default toNSTableView.Style.fullWidth
.
effectiveStyle
documentation:
If the
style
property value isNSTableView.Style.automatic
, then this property contains the resolved style.
.automatic
documentation:
The system resolves the table view style in the following manner:
- If the table view is in a sidebar split-view controller item,
effectiveStyle
resolves toNSTableView.Style.sourceList
.- If the table’s scroll view has a border,
effectiveStyle
resolves toNSTableView.Style.fullWidth
.- Otherwise
effectiveStyle
resolves toNSTableView.Style.inset
. However, if the table needs extra space to fit its column cells,effectiveStyle
resolves toNSTableView.Style.fullWidth
.
Your table view has style set to .automatic
in the Main.storyboard. Which means that the effective style resolves to .inset
-> 10pt around content (based on the rules from the .automatic
documentation).
Open the view debugger with a selected row. You can see the .inset
style effect:
Use .fullWidth
to remove 10pt insets.
You can also test the .automatic
style behavior - try to add a border to the scroll view. Resolves to .fullWidth
.
You probably tried to set the table view style to Full Width in the Interface Builder. It doesn't work. No matter what value you choose, it behaves like .automatic
.
Add the following line to your code to workaround this issue:
tableView?.style = .fullWidth
Works as expected now:
Reported as FB8258910.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With