0

I'm getting some odd behavior. I'm setting a tableHeaderView as follows:

class MyTableViewController: UITableViewController {
    ...
    override func viewDidLoad() {
        ...
        var myHeaderView = NSBundle.mainBundle().loadNibNamed("MyHeaderView", owner: self, options: nil).first as? MyHeaderView
        tableView.tableHeaderView = myHeaderView
        ...
    }
    ...
}

When the view loads up the first time, it displays correctly. Auto-layout gives it a height of 30, and the table header height adheres to it.

When I segue to another view (via tapping a cell in the UITableView), then hit the back button, the UITableView draws with the correct height as well.

However, a split second after everything loads correctly the tableViewHeader resizes itself and covers a bit of the first cell. This is extremely frustrating because I can't seem to figure out where it's happening.

I added some log lines. Here's what it looks like after hitting the back button:

viewWillAppear: header frame is Optional((0.0, 0.0, 375.0, 30.0))
viewDidLayoutSubviews: header frame is Optional((0.0, 0.0, 375.0, 30.0))
viewDidAppear: header frame is Optional((0.0, 0.0, 375.0, 30.0))
viewDidLayoutSubviews: header frame is Optional((0.0, 0.0, 375.0, 49.0))
viewDidLayoutSubviews: header frame is Optional((0.0, 0.0, 375.0, 49.0))

From what I can tell, something out of my control changes the height of the tableViewHeader between viewDidAppear and viewDidLayoutSubviews. I can't correct the size in viewDidLayoutSubviews because it triggers an infinite loop.

I'm at a loss as to what to do to fix this. Everything seems/behaves fine until the view reappears. It also breaks the correct height on transition to/from landscape.

Julian E.
  • 4,687
  • 6
  • 32
  • 49
Albert Bori
  • 9,832
  • 10
  • 51
  • 78

2 Answers2

1

Found a workaround that seems to resolve this issue. (Inspired by this post.) The problem seems to be that the combination of auto-resizing masks and autolayout causes some confusion in how the UITableView tries to determine header size. So, a good option is to use autolayout to connect the header view to the parent table view.

First, set TranslatesAutoresizingMaskIntoConstraints to false:

class MyTableViewController: UITableViewController {
    ...
    var _myHeaderView: MyHeaderView!
    ...
    override func viewDidLoad() {
        ...
        _myHeaderView = NSBundle.mainBundle().loadNibNamed("MyHeaderView", owner: self, options: nil).first as! MyHeaderView
        myHeaderView.setTranslatesAutoresizingMaskIntoConstraints(false)
        tableView.tableHeaderView = myHeaderView
        ...
    }
    ...
}

Then, override the UITableViewController's updateViewConstraints() method to attach constraints:

override func updateViewConstraints() {
    var viewDictionary = ["headerView": _myHeaderView]
    _myHeaderView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[headerView(30)]", options: nil, metrics: nil, views: viewDictionary))
    tableView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[headerView(==tableView)]", options: nil, metrics: nil, views: ["headerView": _myHeaderView, "tableView": tableView]))
    tableView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[headerView]", options: nil, metrics: nil, views: viewDictionary))
    tableView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[headerView]", options: nil, metrics: nil, views: viewDictionary))

    super.updateViewConstraints()
}

This will respond well to view resizing, etc.

Community
  • 1
  • 1
Albert Bori
  • 9,832
  • 10
  • 51
  • 78
0

You can Call tableview.reloadData() to solve the problem.

Jason Yu
  • 311
  • 3
  • 15