I\'ve read a bunch of posts on adding header to UICollectionView. In an iOS 7+ app in Swift, I\'m trying to add a header with a UILabel in it whose height should adjust base
Like the questioner, I had a UICollectionView that contained a header with a single label, whose height I wanted to vary. I created an extension to UILabel to measure the height of a multiline label with a known width:
public extension UILabel {
public class func size(withText text: String, forWidth width: CGFloat) -> CGSize {
let measurementLabel = UILabel()
measurementLabel.text = text
measurementLabel.numberOfLines = 0
measurementLabel.lineBreakMode = .byWordWrapping
measurementLabel.translatesAutoresizingMaskIntoConstraints = false
measurementLabel.widthAnchor.constraint(equalToConstant: width).isActive = true
let size = measurementLabel.systemLayoutSizeFitting(UILayoutFittingCompressedSize)
return size
}
}
Note: the above is in Swift 3 syntax.
Then I implement the header size method of UICollectionViewDelegateFlowLayout as:
extension MyCollectionViewController : UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
let text = textForHeader(inSection: section)
var size = UILabel.size(withAttributedText: text, forWidth: collectionView.frame.size.width)
size.height = size.height + 16
return size
}
}
The work of calculating the header size is delegated to the above UILabel extension. The +16 is a experimentally derived fixed offset (8 + 8) that is based on margins and could be obtained programmatically.
All that's needed in the header callback is just to set the text:
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionElementKindSectionHeader, let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerIdentifier, for: indexPath) as? MyCollectionHeader {
let text = textForHeader(inSection: section)
headerView.label.text = text
return headerView
}
return UICollectionReusableView()
}