There are numerous threads about correctly sizing a tableHeaderView with auto-layout (one such thread) but they tend to pre-date iOS 8.
I have a situation with numerous table views, all with headers, that size correctly under iOS 7 but incorrectly under iOS 8 using the code that most of the aforementioned threads champion. In the controllers for the tables, I have the following method:
- (void)rejiggerTableHeaderView { self.tableView.tableHeaderView = nil; UIView *header = self.headerView; [header setNeedsLayout]; [header layoutIfNeeded]; CGFloat height = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; CGRect headerFrame = header.frame; headerFrame.size.height = height; header.frame = headerFrame; self.tableView.tableHeaderView = header; }
With a multi-line label under iOS 7, this correctly sizes the table view's header like so:
But the same code run under iOS 8 produces the following:
What's the trick to getting -systemLayoutSizeFittingSize: to return the correct size under iOS 8? Here's a sample project that demonstrates the issue.
Changing your headerview function to the following works for me:
- (void)rejiggerTableHeaderView { self.tableView.tableHeaderView = nil; UIView *header = self.headerView; CGRect frame = header.frame; frame.size.width = self.tableView.frame.size.width; header.frame = frame; [header setNeedsLayout]; [header layoutIfNeeded]; CGFloat height = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; CGRect headerFrame = header.frame; headerFrame.size.height = height; header.frame = headerFrame; self.tableView.tableHeaderView = header; }
Problem can be in non-set preferredMaxLayoutWidth
. If you will set it to correct UILabel width, it will determine constraints correctly.
You can go through all UILabel
in header and set preferredMaxLayoutWidth
to label width.
Swift 3 example:
extension UITableView { public func relayoutTableHeaderView() { if let tableHeaderView = tableHeaderView { let labels = tableHeaderView.findViewsOfClass(viewClass: UILabel.self) for label in labels { label.preferredMaxLayoutWidth = label.frame.width } tableHeaderView.setNeedsLayout() tableHeaderView.layoutIfNeeded() tableHeaderView.frame.height = tableHeaderView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height self.tableHeaderView = tableHeaderView } } public func findViewsOfClass<T:UIView>(viewClass: T.Type) -> [T] { var views: [T] = [] for subview in subviews { if subview is T { views.append(subview as! T) } views.append(contentsOf: subview.findViewsOfClass(viewClass: T.self)) } return views } }
UPDATE 2:
Also you can have problem with incorrect height calculation if you have subview with aspect ratio constraint and at the same time proportional to superview width constraint
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