1
votes

I have an app with two tabs, each one containing a table view. The whole is wrapped in a UINavigationController. Here is my storyboard: enter image description here

When I run my app, the first tab is OK:

enter image description here

But on the second one, the table view starts under the navigation bar:

enter image description here

Even worse, when I rotate the screen from the second tab, the second tab is now OK, but the first isn't any more, the table view has an extra margin top:

enter image description here

If I rotate back to portrait from the first tab, I return to the initial state (first tab OK, second tab with table view starting under the navigation bar). In fact, each time I rotate the screen, the displayed tab is OK after the rotation, but the other one isn't.

It seems that I need to do something when my views are shown after a tab change, and that thing seems to be done when the screen rotates, but what is it??

EDIT: I forgot to mention that I don't want to uncheck the "Extend Edges: Under Top/Bottom Bars" checkboxes, because I want my table views to scroll under the nav and tab bars.

1
Yes sure it will work, but then the table view won't scroll under the nav bar, which I don't want.Tim Autin
I can only get this to happen on iOS 8.x simulators. In iOS 9.x simulators it does not occur, so it seems like it may be an iOS bug that Apple has since fixed.TylerP
Oh you're right! I'm targeting >= 8.x though. You can check my answer for a 8 & 9 solution.Tim Autin

1 Answers

1
votes

OK, I got it: first uncheck "Adjust Scroll View Insets" on the UITabBarController, and then add this code on each UITableViewController:

override func viewWillAppear(animated: Bool) {

    // Call super:
    super.viewWillAppear(animated);

    // Update the table view insets:
    updateTableViewInsets();
}

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {

    // Animate:
    coordinator.animateAlongsideTransition({ (UIViewControllerTransitionCoordinatorContext) -> Void in

        // Update the table view insets:
        self.updateTableViewInsets();

    }, completion: { (UIViewControllerTransitionCoordinatorContext) -> Void in })

    // Call super:
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
}

private func updateTableViewInsets() {

    // Get the bars height:
    let navigationBarHeight = self.navigationController!.navigationBar.frame.size.height;
    let statusBarHeight = UIApplication.sharedApplication().statusBarFrame.size.height;
    let tabBarHeight = self.tabBarController!.tabBar.frame.size.height;

    // Create the insets:
    let insets: UIEdgeInsets = UIEdgeInsetsMake(navigationBarHeight + statusBarHeight, 0, tabBarHeight, 0);

    // Update the insets:
    self.tableView.scrollIndicatorInsets = insets;
    self.tableView.contentInset = insets;
}

Now I'm handling the insets myself, and everything is smooth. That should work out of the box IMHO, though...

EDIT: It works out of the box with iOS 9, Apple have probably fixed the bug. The code above works with iOS 8 & 9 (and maybe lower, I didn't try).