This is possible. It is new right alongside the dynamic cell heights introduced in iOS 8.
To do this, use automatic dimension for the section header height, and if desired you can provide an estimated section header height. This can be done in Interface Builder when the table view is selected or programmatically:
tableView.sectionHeaderHeight = UITableView.automaticDimension
tableView.estimatedSectionHeaderHeight = 38
//You can use tableView(_:heightForHeaderInSection:) and tableView(_:estimatedHeightForHeaderInSection:)
//if you need to support different types of headers per section
Then implement tableView(_:viewForHeaderInSection:)
and use Auto Layout to constrain views as desired. Be sure to fully constrain to UITableViewHeaderFooterView
's contentView
, especially top-to-bottom so the height can be determined by the constraints. That's it!
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UITableViewHeaderFooterView()
headerView.translatesAutoresizingMaskIntoConstraints = false
headerView.backgroundView = {
let view = UIView()
view.backgroundColor = myCustomColor
return view
}()
let headerLabel = UILabel()
headerLabel.translatesAutoresizingMaskIntoConstraints = false
headerLabel.text = "Hello World"
headerView.contentView.addSubview(headerLabel)
NSLayoutConstraint.activate([
headerLabel.leadingAnchor.constraint(equalTo: headerView.contentView.leadingAnchor, constant: 16),
headerLabel.trailingAnchor.constraint(equalTo: headerView.contentView.trailingAnchor, constant: -16),
headerLabel.topAnchor.constraint(equalTo: headerView.contentView.topAnchor, constant: 12),
headerLabel.bottomAnchor.constraint(equalTo: headerView.contentView.bottomAnchor, constant: -12)
])
return headerView
}
This can be accomplished by setting (or returning) the estimatedSectionHeaderHeight
on your table view.
If your section header is overlapping your cells after setting estimatedSectionHeaderHeight
, make sure that you're using an estimatedRowHeight
as well.
(I'm adding this answer because the second paragraph contains an answer to an issue that can be found after reading through all of the comments which some might miss.)
Got stuck in the same issue where header was getting zero height untill and unless I provide a fixed height in the delegate for heighForHeaderInSection
.
Tried a lot of solutions which includes
self.tableView.sectionHeaderHeight = UITableView.automaticDimension
self.tableView.estimatedSectionHeaderHeight = 73
But nothing worked. My cell were using proper autolayouts too. Rows were changing their height dynamically by using the following code but section header weren't.
self.tableView.estimatedRowHeight = 135
self.tableView.rowHeight = UITableView.automaticDimension
The fix is extremely simple and weird too but I had to implement the delegate methods instead of 1 line code for the estimatedSectionHeaderHeight
and sectionHeaderHeight
which goes as follows for my case.
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
return 73
}
Swift 4+
working(Tested 100%)
If you need both section as well row with dynamic height based on content then you can use below code:
On viewDidLoad() write this lines:
self.globalTableView.estimatedRowHeight = 20
self.globalTableView.rowHeight = UITableView.automaticDimension
self.globalTableView.sectionHeaderHeight = UITableView.automaticDimension
self.globalTableView.estimatedSectionHeaderHeight = 25;
Now we have set row height and section height by using UITableView Delegate methods:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return UITableView.automaticDimension
}
I tried
self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension;
self.tableView.estimatedSectionHeaderHeight = 25;
but it didn't size correctly header with multiline label. Added this to solve my problem:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Recalculates height
tableView.beginUpdates()
tableView.endUpdates()
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With