I\'m been smashing my head against the wall with this for last 3 or 4 hours and I can\'t seem to figure it out. I have a UIViewController with a full screen UITableView insi
You need to use the UIView systemLayoutSizeFittingSize:
method to obtain the minimum bounding size of your header view.
I provide further discussion on using this API in this Q/A:
How to resize superview to fit all subviews with autolayout?
I've found an elegant way to way to use auto layout to resize table headers, with and without animation.
Simply add this to your View Controller.
func sizeHeaderToFit(tableView: UITableView) {
if let headerView = tableView.tableHeaderView {
let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
var frame = headerView.frame
frame.size.height = height
headerView.frame = frame
tableView.tableHeaderView = headerView
headerView.setNeedsLayout()
headerView.layoutIfNeeded()
}
}
To resize according to a dynamically changing label:
@IBAction func addMoreText(sender: AnyObject) {
self.label.text = self.label.text! + "\nThis header can dynamically resize according to its contents."
}
override func viewDidLayoutSubviews() {
// viewDidLayoutSubviews is called when labels change.
super.viewDidLayoutSubviews()
sizeHeaderToFit(tableView)
}
To animate a resize according to a changes in a constraint:
@IBOutlet weak var makeThisTallerHeight: NSLayoutConstraint!
@IBAction func makeThisTaller(sender: AnyObject) {
UIView.animateWithDuration(0.3) {
self.tableView.beginUpdates()
self.makeThisTallerHeight.constant += 20
self.sizeHeaderToFit(self.tableView)
self.tableView.endUpdates()
}
}
See the AutoResizingHeader project to see this in action. https://github.com/p-sun/Swift2-iOS9-UI
It works for both header view and footer just replace the header with footer
func sizeHeaderToFit() {
if let headerView = tableView.tableHeaderView {
headerView.setNeedsLayout()
headerView.layoutIfNeeded()
let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
var frame = headerView.frame
frame.size.height = height
headerView.frame = frame
tableView.tableHeaderView = headerView
}
}
In my case viewDidLayoutSubviews
worked better. viewWillLayoutSubviews
causes white lines of a tableView
to appear. Also I added checking if my headerView
object already exists.
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
if ( ! self.userHeaderView ) {
// Setup HeaderView
self.userHeaderView = [[[NSBundle mainBundle] loadNibNamed:@"SSUserHeaderView" owner:self options:nil] objectAtIndex:0];
[self.userHeaderView setNeedsLayout];
[self.userHeaderView layoutIfNeeded];
CGFloat height = [self.userHeaderView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
CGRect headerFrame = self.userHeaderView.frame;
headerFrame.size.height = height;
self.userHeaderView.frame = headerFrame;
self.tableView.tableHeaderView = self.userHeaderView;
// Update HeaderView with data
[self.userHeaderView updateWithProfileData];
}
}
For iOS 12 and above, the following steps will ensure autolayout works properly in both your table and the header.
[headerV setNeedsLayout]; [headerV layoutIfNeeded];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 *NSEC_PER_SEC), dispatch_get_main_queue(), ^{ [tableV.tableHeaderView setNeedsLayout]; [tableV.tableHeaderView layoutIfNeeded]; [tableV reloadData];});
This solution resizes the tableHeaderView and avoids infinite loop in the viewDidLayoutSubviews()
method I was having with some of the other answers here:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let headerView = tableView.tableHeaderView {
let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).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
}
}
}
See also this post: https://stackoverflow.com/a/34689293/1245231