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 UILabel
s 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:
-
Make sure your data source is not random text that doesn't depend on the section index.
-
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)
}
}