Dynamic height of header with multiline UILabel in UITableView

Assuming you have got your Section Header setup using a XIB file, it is probably a constraint issue that is causing incorrect sizes, among other things.

I have put together a list of common errors that can happen when working with dynamic section headers. Please check them one-by-one, to see which one resolves your issue.

1. Make sure your Constraints are setup correctly.

Open up your Section Header XIB and make sure that there are enough constraints for UITableView to calculate the view's height. Notice that I have setup the bottom constraint with a priority of 999. This is important because of Step 3.

2. Make sure your UILabel can grow

Set the "Number of Lines" of both UILabels to zero as shown below.

3. Adjust the Content Hugging and Compression Resistance

Select your UILabels, and click the "Size Inspector" ().

At the bottom, set these values to 1000 so that Auto Layout treats them as important as your other constraints.

  • Content Hugging Priority > Vertical

This sets how well the UILabel's height should hugs its text content.

  • Compression Resistance Priority > Vertical

This sets how much the UILabel should resist shrinking its height beyond the height of its content.

Like so:

4. Return a reasonable value in estimatedHeightForHeaderInSection

func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
    return 44.0
}

5. Compile and run!

Your section headers should now be properly sizing.

Notes:

  1. Make sure your data source is not random text that doesn't depend on the section index.

  2. If your section headers overlap or are improperly sized, make sure that your data source isn't changing while the UITableView is scrolling.


step 1: calculate the height of both UILabel text in heightForHeaderInSection method.

step 2: return the max height in heightForHeaderInSection.

and make sure to set UILabel's numberOfLines property to 0.

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    let font = UIFont.systemFont(ofSize: 23)
    let height1 = "section \(section) label1 text".height(withConstrainedWidth: UIScreen.main.bounds.width/2 , font: font)  
    let height2 =  "section \(section) label2 text".height(withConstrainedWidth: UIScreen.main.bounds.width/2 , font: font) 
    return max(height1,height2)
}

Here I'm using an extension of String to calculate the height of the UILabel text.

extension String {
    func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
        let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
    
        return ceil(boundingBox.height)
    }
}