Swift Solution
This solution targets iOS 8 and above in Swift.
My app's root view controller is a navigation controller. Initially this navigation controller has one UIViewController
on its stack which I will call the parent view controller.
When the user taps a nav bar button, the parent view controller toggles between two child view controllers on its view using the containment API (toggling between mapped results and listed results). The parent view controller holds references to the two child view controllers. The second child view controller is not created until the first time the user taps the toggle button. The second child view controller is a table view controller and exhibited the issue where it underlaps the navigation bar regardless of how its automaticallyAdjustsScrollViewInsets
property was set.
To fix this I call adjustChild:tableView:insetTop
(shown below) after the child table view controller is created and in the parent view controller's viewDidLayoutSubviews
method.
The child view controller's table view and the parent view controller's topLayoutGuide.length
are passed to the adjustChild:tableView:insetTop
method like this...
// called right after childViewController is created
adjustChild(childViewController.tableView, insetTop: topLayoutGuide.length)
The adjustChild method...
private func adjustChild(tableView: UITableView, insetTop: CGFloat) {
tableView.contentInset.top = insetTop
tableView.scrollIndicatorInsets.top = insetTop
// make sure the tableview is scrolled at least as far as insetTop
if (tableView.contentOffset.y > -insetTop) {
tableView.contentOffset.y = -insetTop
}
}
The statement tableView.scrollIndicatorInsets.top = insetTop
adjusts the scroll indicator on the right side of the table view so it begins just below the navigation bar. This is subtle and is easily overlooked until you become aware of it.
The following is what viewDidLayoutSubviews
looks like...
override func viewDidLayoutSubviews() {
if let childViewController = childViewController {
adjustChild(childViewController.tableView, insetTop: topLayoutGuide.length)
}
}
Note that all the code above appears in the parent view controller.
I figured this out with help from Christopher Pickslay's answer to the question "iOS 7 Table view fail to auto adjust content inset".