dev_mush
dev_mush

Reputation: 2196

Why content insets of a UITableView inside a UIPageViewController get messy right after an interaction?

I've created a Page-Based Application and hacked it a bit for some experiments; my simple aim is to have a UIPageViewController whose pages will contain a UIViewController holding a UITableView (after further inspection, the outcome of my experiment is the same if I use a UITableViewController instead). To do this I've simply edited the project template, and added the UIPageViewController as an embedded view of the RootViewController using Storyboard's ContainerView object, as you can see in this screenshot:

storyboard's controllers

Every controller is configured via storyboard to automatically adjust scroll view's content inset, and if I start the project with this configuration everything looks fine, and the DataViewController's tableview has its content insets properly adjusted right under the navigation bar as expected; however, as the user makes an interaction with the tableview, the content insets break and the tableview underlaps the navigation bar:

content inset issue with uipageviewcontroller and a tableview

I have been able to fix this by manually setting the content insets in DataViewController's viewDidLayoutSubview method, and by disabling Adjusts Scroll View Insets on any controller, so I don't need this as an answer to solve my problem. My question is why the content insets are properly set right after the first controller gets loaded from the storyboard the first time, and why they break after any kind of user interaction.

If you need to test it directly, here's a link to the project

Upvotes: 9

Views: 6163

Answers (3)

javorosas
javorosas

Reputation: 769

Found an elegant solution:

  1. From your storyboard, select your UIPageViewController
  2. In the Attributes inspector, uncheck the option ViewController => Extend Edges => Under Top Bars
  3. That's all, no weird UI hacks

Upvotes: 9

Mike Abdullah
Mike Abdullah

Reputation: 15003

I'm not 100% sure it's what you're running into, but here's some explanation regarding your setup:

By default, UIViewControllers tend to be configured to extend their content behind non-opaque bars, and to adjust scroll view insets. In your setup above this means that the container VC:

  • Extends its content so as to appear behind the navigation bar
  • Sets its scrollview's .contentInset and .scrollIndicatorInsets to be the same height as the navigation bar

"But, ah!" I hear you say, "that container view controller doesn't have a scroll view". Well this is the tricky bit:

It seems UIViewController's definition of "my scroll view" is rather simplistically, "the first scroll view I come to when searching down through my view hierarchy".

UIPageViewController happens to be implemented using a scroll view. So the container VC finds that scroll view, and adjusts its top insets. This is not really what you want; it confuses the page controller, and tends to upset layout at some point.

The simple solution there is simply to turn off .automaticallyAdjustsScrollViewInsets for the container view controller.

You then need to solve the next problem of your table view needing some kind of top insets to account for the navigation bar. So far it seems to me the best way to do this is manually either in the storyboard, or code.

Upvotes: 15

Vik
Vik

Reputation: 1927

Have you tried fixing the Auto Layout constraint in the container view of the Root view controller in the Storyboard (that is, the top space constraint should be set related to the Top Layout Guide and not the Superview, with constant = 0)? You will only lose the effect of the Table View scrolling under the Navigation Bar

Upvotes: 0

Related Questions