NSOutlineView spacing between items is incorrect

Viewed 179

I have an NSOutlineView, and the space between items 1 and 2 is greater than the spacing between all other items. These are group items. The outline view is very bare bones. Below is my code, and below that is an image of the issue I am referring to:

var sections: [SidebarSection] = [
    SidebarSection(title: "Section 1", items: ["1", "2", "3", "4", "5"]),
    SidebarSection(title: "Section 2", items: ["1", "2"]),
    SidebarSection(title: "Section 3", items: ["1", "2"]), 
    SidebarSection(title: "Section 4", items: ["1", "2"]), 
    SidebarSection(title: "Section 5", items: ["1", "2"])]

private let outlineView: SidebarOutlineView = SidebarOutlineView()

extension SidebarViewController: NSOutlineViewDataSource {

    func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
        return item is SidebarSection
    }
    
    func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
        if let section = item as? SidebarSection {
            return section.items[index]
        }
    
        return sections[index]
    }

    func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
        if let section = item as? SidebarSection {
            return section.items.count
        }
        return sections.count
    }
}

extension SidebarViewController: NSOutlineViewDelegate {

    func outlineView(_ outlineView: NSOutlineView, heightOfRowByItem item: Any) -> CGFloat {
        return 30
    }

    func outlineView(_ outlineView: NSOutlineView, isGroupItem item: Any) -> Bool {
        return item is SidebarSection
    }

    func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
        let view = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "SidebarPlaylistCell"), owner: self) as! SidebarPlaylistCell
        view.wantsLayer = true
        view.textLabel.stringValue = (item as? SidebarSection)?.title ?? ""
        view.imgView.wantsLayer = true
        view.imgView.layer?.backgroundColor = NSColor.red.cgColor
        return view
    }
}

extension SidebarViewController {

   func layout() {
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(scrollView)
    
        scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    
        scrollView.documentView = outlineView
    
        outlineView.headerView = nil
    
        outlineView.delegate = self
        outlineView.dataSource = self
         outlineView.intercellSpacing = NSSize(width: 0, height: 0)
        scrollView.hasVerticalScroller = true
        scrollView.hasHorizontalScroller = false
        scrollView.wantsLayer = true
    
        view.layer?.backgroundColor = NSColor.blue.cgColor
    }
}


final class SidebarOutlineView: NSOutlineView {

    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        let column: NSTableColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier("col1"))
        column.isEditable = false
        column.minWidth = 0
        addTableColumn(column)
        outlineTableColumn = column
    
        register(NSNib(nibNamed: "SidebarPlaylistCell", bundle: nil), forIdentifier: NSUserInterfaceItemIdentifier(rawValue: "SidebarPlaylistCell"))
        selectionHighlightStyle = .sourceList
        indentationPerLevel = 6.0
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
}

enter image description here

1 Answers

This behavior can be controlled by a boolean flag floatsGroupRows, which is set to true by default. So by adding:

outlineView.floatsGroupRows = false

you get the desired behavior.

Documentation can be found here: https://developer.apple.com/documentation/appkit/nstableview/1528624-floatsgrouprows?language=swift

A Boolean value indicating whether the table view draws grouped rows as if they are floating.

Quick Test

quick test

Meaning of floatGroupRows

The effect of floatsGroupRows can be seen better in an animated graphic. During a scroll operation, the current GroupItem remains floating on top:

scroll demo of floatsGroupRows

Related