Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

-systemLayoutSizeFittingSize: returning incorrect height for tableHeaderView under iOS 8

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.

like image 593
Jeff Nouwen Avatar asked Oct 15 '14 20:10

Jeff Nouwen


2 Answers

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; } 
like image 68
Wilmar Avatar answered Sep 29 '22 06:09

Wilmar


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

like image 34
Vitalii Gozhenko Avatar answered Sep 29 '22 07:09

Vitalii Gozhenko