I've implemented a custom FlowLayout subclass, which apparently has precluded me from adding a headerView via the storyboard (the check box is gone). Is there any other way to do so using storyboards?
There are some answers about how to add a headerView programmatically but they're in objective-C, how can I add one using Swift?
The below doesn't produce a header view and I can't figure out why?
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! } My Layout class:
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 } } 2 Answers
Answers 1
You can add header view in storyboard, drag a "Collection Reusable View" and drop it inside the collectionView, then set its class and identifier in storyboard. Or you can register your custom header class programmatically as shown in your code.
self.collectionView!.registerClass(PinHeaderView.self, forSupplementaryViewOfKind:UICollectionElementKindSectionHeader, withReuseIdentifier: headerIdentifier)
viewForSupplementaryElementOfKind delegate method is incomplete, case UICollectionElementKindSectionFooter isn't handled, do the same for footer view as what you did for header view. If you don't see it, set borderWidth of header view's layer to a value greater than 0, it might show up.
Answers 2
Why are you using PinterestLayoutAttributes(forCellWithIndexPath: indexPath) in method layoutAttributesForSupplementaryViewOfKind?
You should use PinterestLayoutAttributes(forSupplementaryViewOfKind elementKind: String, withIndexPath indexPath: NSIndexPath).
You are generating layout attributes for cell instead of suplementary view. As a result your layout attributes don't contain right category type and view kind. That's why even if you register class for suplementary view - collection view doesn't layout its instances.
0 comments:
Post a Comment