0

I'm trying to create a UITableView with a header view using autolayout using storyboards. It looks fine in Xcode, but when I run the app, it does not look the same.

In Xcode: enter image description here

In the app: enter image description here

The image has a constraint for 150x150, and there are 8-high constraints between the top-image, image-middle label, middle description-label and description label-bottom.

Both labels have numberOfRows set to 0 and lineBreakMode set to ByWordWrapping.

I have tried settings the frame via:

if let headerView = self.tableView.tableHeaderView {
    headerView.setNeedsLayout()
    headerView.layoutIfNeeded()
    let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
    println("Setting height to \(height)")

    var headerFrame = headerView.frame
    headerFrame.size.height = height
    headerView.frame = headerFrame
    self.tableView.tableHeaderView = headerView
}

One of the original issues was that I had some erroneous constraints (that for some reason Xcode only started complaining about today), so I have removed those and set a contentHuggingPriority of 252 (higher than all others) on the app name label. When I resize the header view manually in the storyboard the image and app name label stay the same height, and the description label grows. It would appear that the apps uses the size of the header in the storyboard at run time, and doesn't get the height from its children.

Joseph Duffy
  • 4,566
  • 9
  • 38
  • 68

1 Answers1

2

Answering my own question here:

There are 2 steps that seem to get this to work. The first is in ViewDidLoad, and the second is in viewDidLayoutSubviews:

var headerView: UIView!

override func viewDidLoad() {
    super.viewDidLoad()

    if let currentTableHeaderView = self.tableView.tableHeaderView {
        currentTableHeaderView.removeFromSuperview()
    }
    // Setting the table header view with a height of 0.01 fixes a bug that adds a gap between the
    // tableHeaderView (once added) and the top row. See: http://stackoverflow.com/a/18938763/657676
    self.tableView.tableHeaderView = UIView(frame: CGRectMake(0, 0, CGRectGetWidth(self.tableView.frame), 0.01))
    self.headerView = AboutTableViewHeaderView(frame: CGRectZero)
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    if let tableHeaderView = self.headerView {
        var frame = CGRectZero
        frame.size.width = self.tableView.bounds.size.width
        frame.size.height = tableHeaderView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
        if self.tableView.tableHeaderView == nil || !CGRectEqualToRect(frame, tableHeaderView.frame) {
            tableHeaderView.frame = frame
            tableHeaderView.layoutIfNeeded()
            self.tableView.tableHeaderView = tableHeaderView
        }
    }
}

Hopefully that all makes sense. The viewDidLayoutSubview code is via http://osdir.com/ml/general/2014-06/msg19399.html

Joseph Duffy
  • 4,566
  • 9
  • 38
  • 68
  • In my case with `viewDidLayoutSubviews` I could see the view appearing with the wrong size, and recalculating with a little bit of lag. Calling the same code in `viewWillLayoutSubviews` made the view appear with the needed height. – jdev Jan 26 '17 at 08:57