Setting tableHeaderView height dynamically
Copied from this post. (Make sure you see it if you're looking for more details)
override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() if let headerView = tableView.tableHeaderView { let height = headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height var headerFrame = headerView.frame //Comparison necessary to avoid infinite loop if height != headerFrame.size.height { headerFrame.size.height = height headerView.frame = headerFrame tableView.tableHeaderView = headerView } }}
Determining the header's frame size using
header.systemLayoutSizeFitting(UILayoutFittingCompressedSize)
as suggested in the answers above didn't work for me when my header view consisted of a single multiline label. With the label's line break mode set to wrap, the text just gets cut off:
Instead, what did work for me was using the width of the table view and a height of 0 as the target size:
header.systemLayoutSizeFitting(CGSize(width: tableView.bounds.width, height: 0))
Putting it all together (I prefer to use an extension):
extension UITableView { func updateHeaderViewHeight() { if let header = self.tableHeaderView { let newSize = header.systemLayoutSizeFitting(CGSize(width: self.bounds.width, height: 0)) header.frame.size.height = newSize.height } }}
And call it like so:
override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() tableView.updateHeaderViewHeight()}
More condensed version of OP's answer, with the benefit of allowing layout to happen naturally (note this solution uses viewWillLayoutSubviews):
override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() if let header = tableView.tableHeaderView { let newSize = header.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) header.frame.size.height = newSize.height }}
Thanks to TravMatth for the original answer.