Dynamic UICollectionView header size based on UILabel

前端 未结 8 1982
梦谈多话
梦谈多话 2020-12-08 04:51

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

8条回答
  •  不知归路
    2020-12-08 05:46

    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()
    }
    

提交回复
热议问题