Reputation: 51
I have an ViewController with a NSCollectionView with Headers and Items. At a first glance everything looks fine:
As soon as I resize the window, one header becomes the size of an item – and the other headers disappear:
This is my code:
extension ViewController:NSCollectionViewDataSource {
static let picItem = "PictureItem"
static let headerItem = "HeaderItem"
func numberOfSections(in collectionView: NSCollectionView) -> Int {
return 3
}
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
return 15
}
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
let itemView = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: ViewController.picItem), for: indexPath)
return itemView
}
func collectionView(_ collectionView: NSCollectionView, viewForSupplementaryElementOfKind kind: NSCollectionView.SupplementaryElementKind, at indexPath: IndexPath) -> NSView {
let headerView = collectionView.makeSupplementaryView(ofKind: kind, withIdentifier: NSUserInterfaceItemIdentifier(rawValue: ViewController.headerItem), for: indexPath)
return headerView
}
}
extension ViewController:NSCollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> NSSize {
return NSSize(width: 0, height: 20)
}
}
The storyboard:
What's going on here? What did I miss?
HeaderItem.swift
class HeaderItem: NSCollectionViewItem {
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
view.wantsLayer = true
view.layer?.backgroundColor = NSColor.green.cgColor
}
}
HeaderItem.xib
The outlet view of the HeaderItem object is the CustomView.
Upvotes: 0
Views: 649
Reputation: 498
I think the best way is follow Apple guidelines for the new approach . First create UICollectionView Layout where specify all geometry params for header, cells and footers, for example:
import UIKit
import Combine
import Resolver
class DeliveryController: UIViewController {
var dataSource: UICollectionViewDiffableDataSource<Order, OrderItem>! = nil
func createLayout() -> UICollectionViewLayout {
let itemWidth: CGFloat = 140.0
let itemHeight: CGFloat = 140.0
let headerHeight: CGFloat = 140.0
let footerHeight: CGFloat = 68.0
let config = UICollectionViewCompositionalLayoutConfiguration()
config.interSectionSpacing = 10.0
let layout = UICollectionViewCompositionalLayout(sectionProvider: {
(sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
let order = self.orders[sectionIndex]
let item = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(
widthDimension: .absolute(itemWidth), heightDimension: .absolute(itemHeight)))
item.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 0, bottom: 0, trailing: 10)
let containerGroup = NSCollectionLayoutGroup.horizontal(
layoutSize: NSCollectionLayoutSize(widthDimension: .absolute(itemWidth), heightDimension: .estimated(itemHeight)), subitems: [item])
let section = NSCollectionLayoutSection(group: containerGroup)
section.orthogonalScrollingBehavior = UICollectionLayoutSectionOrthogonalScrollingBehavior.continuous
let sectionHeader = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(headerHeight)),
elementKind: DeliveryController.sectionHeaderElementKind,
alignment: .top)
let sectionFooter = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(footerHeight)),
elementKind: DeliveryController.sectionFooterElementKind,
alignment: .bottom)
if order.hasDriver {
section.boundarySupplementaryItems = [sectionHeader, sectionFooter]
} else {
section.boundarySupplementaryItems = [sectionHeader]
}
return section
}, configuration: config)
return layout
}
Then configureHierarchy using given layout:
func configureHierarchy(in view: UIView, top: UIView, bottom: UIView) {
collectionView = UICollectionView(frame: .zero /* create with zero frame and use constarins after we adding collectionView as subview */, collectionViewLayout: createLayout())
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
collectionView.backgroundColor = .white
view.addSubview(collectionView)
collectionView.anchor(top: top.bottomAnchor, left: view.leftAnchor, bottom: bottom.topAnchor, right: view.rightAnchor, paddingTop: 8, paddingLeft: 0, paddingBottom: 2, paddingRight: 0)
collectionView.delegate = self
}
And then DataSource:
func configureDataSource() {
let cellRegistration = UICollectionView.CellRegistration<OrderItemCell, OrderItem> { (cell, indexPath, item) in
cell.item = item
}
dataSource = UICollectionViewDiffableDataSource<Order, OrderItem>(collectionView: collectionView) {
(collectionView: UICollectionView, indexPath: IndexPath, item: OrderItem) -> UICollectionViewCell? in
return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item)
}
let headerRegistration = UICollectionView.SupplementaryRegistration
<OrderHeaderView>(elementKind: "Header") {
(supplementaryView, string, indexPath) in
let order = self.orders[indexPath.section]
supplementaryView.order = order
}
let footerRegistration = UICollectionView.SupplementaryRegistration
<OrderFooterView>(elementKind: "Footer") {
(supplementaryView, string, indexPath) in
let order = self.orders[indexPath.section]
supplementaryView.order = order
supplementaryView.delegate = self
}
dataSource.supplementaryViewProvider = { (view, kind, index) in
let order = self.orders[index.section]
if kind == DeliveryController.sectionHeaderElementKind {
return self.collectionView.dequeueConfiguredReusableSupplementary(using: headerRegistration, for: index)
} else if order.hasDriver {
return self.collectionView.dequeueConfiguredReusableSupplementary(using: footerRegistration, for: index)
}
return nil
}
var snapshot = NSDiffableDataSourceSnapshot<Order, OrderItem>()
orders.forEach { order in
snapshot.appendSections([order])
snapshot.appendItems(order.items, toSection: order)
}
dataSource.apply(snapshot, animatingDifferences: false)
}
}
Upvotes: 0