Agregar un HeaderView a CollectionView cuando usa FlowLayout personalizado (Swift)

He implementado una subclass FlowLayout personalizada, lo que aparentemente me ha impedido agregar una headerView través del storyboard (la checkbox desaparece). ¿Hay alguna otra manera de hacerlo usando storyboards ?

Hay algunas respuestas sobre cómo agregar un headerView progtwigción, pero están en el objective-C , ¿cómo puedo agregar uno usando Swift ?

El siguiente no produce una vista de encabezado y no puedo entender por qué.

  CollectionViewController { override func viewDidLoad() { super.viewDidLoad() // Setup Header self.collectionView!.registerClass(PinHeaderView.self, forSupplementaryViewOfKind:UICollectionElementKindSectionHeader, withReuseIdentifier: headerIdentifier) } override func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView { //1 switch kind { //2 case UICollectionElementKindSectionHeader: //3 let headerView = collectionView.dequeueReusableSupplementaryViewOfKind(kind,withReuseIdentifier: "PinHeaderView", forIndexPath: indexPath) as! PinHeaderView headerView.pinHeaderLabel.text = boardName return headerView default: //4 fatalError("Unexpected element kind") } } } class PinHeaderView: UICollectionReusableView { @IBOutlet weak var pinHeaderLabel: UILabel! } 

Mi class de layout:

 import UIKit protocol PinterestLayoutDelegate { // 1. Method to ask the delegate for the height of the image func collectionView(collectionView:UICollectionView, heightForPhotoAtIndexPath indexPath:NSIndexPath , withWidth:CGFloat) -> CGFloat // 2. Method to ask the delegate for the height of the annotation text func collectionView(collectionView: UICollectionView, heightForAnnotationAtIndexPath indexPath: NSIndexPath, withWidth width: CGFloat) -> CGFloat func columnsForDevice() -> Int } class PinterestLayoutAttributes:UICollectionViewLayoutAttributes { // 1. Custom attribute var photoHeight: CGFloat = 0.0 var headerHeight: CGFloat = 0.0 // 2. Override copyWithZone to conform to NSCopying protocol override func copyWithZone(zone: NSZone) -> AnyObject { let copy = super.copyWithZone(zone) as! PinterestLayoutAttributes copy.photoHeight = photoHeight return copy } // 3. Override isEqual override func isEqual(object: AnyObject?) -> Bool { if let attributtes = object as? PinterestLayoutAttributes { if( attributtes.photoHeight == photoHeight ) { return super.isEqual(object) } } return false } } class PinterestLayout: UICollectionViewLayout { //1. Pinterest Layout Delegate var delegate:PinterestLayoutDelegate! //2. Configurable properties //moved numberOfColumns var cellPadding: CGFloat = 6.0 //3. Array to keep a cache of attributes. private var cache = [PinterestLayoutAttributes]() //4. Content height and size private var contentHeight:CGFloat = 0.0 private var contentWidth: CGFloat { let insets = collectionView!.contentInset return CGRectGetWidth(collectionView!.bounds) - (insets.left + insets.right) } override class func layoutAttributesClass() -> AnyClass { return PinterestLayoutAttributes.self } override func prepareLayout() { // 1. Only calculate once //if cache.isEmpty { // 2. Pre-Calculates the X Offset for every column and adds an array to increment the currently max Y Offset for each column let numberOfColumns = delegate.columnsForDevice() let columnWidth = contentWidth / CGFloat(numberOfColumns) var xOffset = [CGFloat]() for column in 0 ..< numberOfColumns { xOffset.append(CGFloat(column) * columnWidth ) } var column = 0 var yOffset = [CGFloat](count: numberOfColumns, repeatedValue: 0) // 3. Iterates through the list of items in the first section for item in 0 ..< collectionView!.numberOfItemsInSection(0) { let indexPath = NSIndexPath(forItem: item, inSection: 0) // 4. Asks the delegate for the height of the picture and the annotation and calculates the cell frame. let width = columnWidth - cellPadding*2 let photoHeight = delegate.collectionView(collectionView!, heightForPhotoAtIndexPath: indexPath , withWidth:width) let annotationHeight = delegate.collectionView(collectionView!, heightForAnnotationAtIndexPath: indexPath, withWidth: width) let height = cellPadding + photoHeight + annotationHeight + cellPadding let frame = CGRect(x: xOffset[column], y: yOffset[column], width: columnWidth, height: height) let insetFrame = CGRectInset(frame, cellPadding, cellPadding) // 5. Creates an UICollectionViewLayoutItem with the frame and add it to the cache let attributes = PinterestLayoutAttributes(forCellWithIndexPath: indexPath) attributes.photoHeight = photoHeight attributes.frame = insetFrame cache.append(attributes) // 6. Updates the collection view content height contentHeight = max(contentHeight, CGRectGetMaxY(frame)) yOffset[column] = yOffset[column] + height column = column >= (numberOfColumns - 1) ? 0 : ++column } //} } override func layoutAttributesForSupplementaryViewOfKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? { let attributes = PinterestLayoutAttributes(forSupplementaryViewOfKind: elementKind, withIndexPath: indexPath) attributes.headerHeight = 100.0 attributes.frame = (self.collectionView?.frame)! return attributes } override func collectionViewContentSize() -> CGSize { return CGSize(width: contentWidth, height: contentHeight) } override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? { var layoutAttributes = [UICollectionViewLayoutAttributes]() // Loop through the cache and look for items in the rect for attributes in cache { if CGRectIntersectsRect(attributes.frame, rect ) { layoutAttributes.append(attributes) } } return layoutAttributes } } 

Puede agregar vista de encabezado en el guión gráfico, arrastrar una "Vista de colección reutilizable" y soltarla dentro de la colecciónView, luego establecer su class e identifier en el guión gráfico. O puede registrar su class de encabezado personalizada mediante progtwigción como se muestra en su código.

self.collectionView!.registerClass(PinHeaderView.self, forSupplementaryViewOfKind:UICollectionElementKindSectionHeader, withReuseIdentifier: headerIdentifier)

viewForSupplementaryElementOfKind método viewForSupplementaryElementOfKind delegate está incompleto, caso UICollectionElementKindSectionFooter no se maneja, haga lo mismo para la vista del pie de página que lo que hizo para la vista del encabezado. Si no lo ve, establezca el borderWidth del borderWidth de la capa de la vista de encabezado en un valor mayor que 0, podría aparecer.

¿Por qué estás usando PinterestLayoutAttributes(forCellWithIndexPath: indexPath) en el método layoutAttributesForSupplementaryViewOfKind ?

Debe usar PinterestLayoutAttributes(forSupplementaryViewOfKind elementKind: String, withIndexPath indexPath: NSIndexPath) .

Está generando attributes de layout para la celda en lugar de la vista complementaria. Como resultado, los attributes de layout no contienen el tipo de categoría y el tipo de vista correctos. Es por eso que incluso si registra una class para una vista suplementaria, la vista de colección no distribuye sus instancias.

Dentro de la function prepareForLayout , agregue un object más attributes para el encabezado. Puede agregarlo al caching al final así:

  // Add Attributes for section header let headerAtrributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, with: IndexPath(item: 0, section: 0)) headerAtrributes.frame = CGRect(x: 0, y: 0, width: self.collectionView!.bounds.size.width, height: 50) cache.append(headerAtrributes)