问题描述
我有一个带有带有标题和项目的 NSCollectionView 的 ViewController。乍一看,一切都很好:
一旦我调整窗口大小,一个标题就会变成一个项目的大小——而其他标题就会消失:
这是我的代码:
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)
}
}
故事板:
这是怎么回事?我错过了什么?
附加代码
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
HeaderItem 对象的出口视图是 CustomView。
解决方法
我认为最好的方法是遵循 Apple guidelines 的新方法。首先创建 UICollectionView 布局,其中指定页眉、单元格和页脚的所有几何参数,例如:
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
}
然后使用给定的布局配置层次结构:
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
}
然后是数据源:
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,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)
}
}