Issue #437

Normal

Use Omnia for itemId extension

HeaderCell.swift

final class HeaderCell: NSView, NSCollectionViewSectionHeaderView {
    let label: NSTextField = withObject(NSTextField(labelWithString: "")) {
        $0.textColor = R.color.header
        $0.font = R.font.header
        $0.alignment = .left
        $0.lineBreakMode = .byTruncatingTail
    }

    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)

        addSubviews([label])

        activate(
            label.anchor.centerY,
            label.anchor.left.constant(8)
        )
    }

    required init?(coder: NSCoder) {
        fatalError()
    }
}

ViewController.swift

collectionView.register(
    HeaderCell.self,
    forSupplementaryViewOfKind: NSCollectionView.elementKindSectionHeader,
    withIdentifier: HeaderCell.itemId
)

func collectionView(_ collectionView: NSCollectionView, viewForSupplementaryElementOfKind kind: NSCollectionView.SupplementaryElementKind, at indexPath: IndexPath) -> NSView {

    if kind == NSCollectionView.elementKindSectionHeader {
        let view = collectionView.makeSupplementaryView(
            ofKind: kind,
            withIdentifier: HeaderCell.itemId,
            for: indexPath
        ) as! HeaderCell

        let menu = app.menus[indexPath.section]
        view.label.stringValue = menu.name

        return view
    } else {
        return NSView()
    }
}

In generic subclass

If use CollectionViewHandler from Omnia, then need to add @objc due to a bug in Swift compiler for subclassing generic class

@objc (collectionView:viewForSupplementaryElementOfKind:atIndexPath:)

MyHandler.swift

import AppKit
import Omnia

class MyHandler: CollectionViewHandler<App.Key, KeyCell> {
    override init() {
        super.init()

        layout.headerReferenceSize = NSSize(width: 300, height: 30)

        collectionView.register(
            HeaderCell.self,
            forSupplementaryViewOfKind: NSCollectionView.elementKindSectionHeader,
            withIdentifier: HeaderCell.itemId
        )
    }

    @objc (collectionView:viewForSupplementaryElementOfKind:atIndexPath:)
    func collectionView(_ collectionView: NSCollectionView, viewForSupplementaryElementOfKind kind: NSCollectionView.SupplementaryElementKind, at indexPath: IndexPath) -> NSView {
        
        if kind == NSCollectionView.elementKindSectionHeader {
            let view = collectionView.makeSupplementaryView(
                ofKind: kind,
                withIdentifier: HeaderCell.itemId,
                for: indexPath
            ) as! HeaderCell

            let menu = app.menus[indexPath.section]
            view.label.stringValue = menu.name

            return view
        } else {
            return NSView()
        }
    }
}

Use Omnia

Use CollectionViewSectionHandler from Omnia

class SectionHandler: CollectionViewSectionHandler<App.Key, KeyCell, HeaderCell> {

}

sectionHandler.configureHeader = { section, view in
    view.label.stringValue = section.name
}

sectionHandler.configure = { item, cell in
    cell.shortcutLabel.stringValue = item.shortcut
    cell.nameLabel.stringValue = item.name
}

sectionHandler.itemSize = { [weak self] in
    guard let self = self else {
        return .zero
    }

    let width = self.sectionHandler.collectionView.frame.size.width
        - self.sectionHandler.layout.sectionInset.left
        - self.sectionHandler.layout.sectionInset.right

    return CGSize(width: width, height: 18)
}

Read more