I have a UIPageViewController
with translucent status bar and navigation bar. Its topLayoutGuide
is 64 pixels, as expected.
However, the ch
This is the approach for the known guide length. Create constrains not to guides, but to view's top with fixed constants assuming guide distance will be.
I might be wrong, but in my opinion the behaviour is correct. The topLayout value can be used by the container view controller to layout its view's subviews.
The reference says:
To use a top layout guide without using constraints, obtain the guide’s position relative to the top bound of the containing view.
In the parent, relative to the containing view, the value will be 64.
In the child, relative to the containing view (the parent), the value will be 0.
In the container View Controller you could use the property this way:
- (void) viewWillLayoutSubviews {
CGRect viewBounds = self.view.bounds;
CGFloat topBarOffset = self.topLayoutGuide.length;
for (UIView *view in [self.view subviews]){
view.frame = CGRectMake(viewBounds.origin.x, viewBounds.origin.y+topBarOffset, viewBounds.size.width, viewBounds.size.height-topBarOffset);
}
}
The Child view controller does not need to know that there are a Navigation and a Status bar : its parent will have already laid out its subviews taking that into account.
If I create a new page based project, embed it in a navigation controller, and add this code to the parent view controllers it seems to be working fine:
you can add a constraint in the storyboard and change it in viewWillLayoutSubviews
something like this:
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
self.topGuideConstraint.constant = [self.parentViewController.topLayoutGuide length];
}
In case if you have UIPageViewController
like OP does and you have for example collection view controllers as children. Turns out the fix for content inset is simple and it works on iOS 8:
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
UIEdgeInsets insets = self.collectionView.contentInset;
insets.top = self.parentViewController.topLayoutGuide.length;
self.collectionView.contentInset = insets;
self.collectionView.scrollIndicatorInsets = insets;
}
I think the guides are definitely meant to be set for nested child controllers. For example, suppose you have:
That would make sense: it means that the nested view controller can set constraints to prevent unwanted overlap, just like a top-level one. It doesn't have to care that it's nested, or where on the screen its parent is displaying it, and the parent view controller doesn't need to know how the child wants to interact with the status bar.
That also seems to be what the documentation--or some of the documentation, at least--says:
The top layout guide indicates the distance, in points, between the top of a view controller’s view and the bottom of the bottommost bar that overlays the view
(https://developer.apple.com/library/ios/documentation/UIKit/Reference/UILayoutSupport_Protocol/Reference/Reference.html)
That doesn't say anything about only working for top-level view controllers.
But, I don't know if this is what actually happens. I've definitely seen child view controllers with nonzero topLayoutGuides, but I'm still figuring out the quirks. (In my case the top guide should be zero, since the view isn't at the top of the screen, which is what I'm banging my head against at the moment...)
Not sure if anyone still got problem with this, as I still did a few minutes ago.
My problem is like this (source gif from https://knuspermagier.de/2014-fixing-uipageviewcontrollers-top-layout-guide-problems.html).
For short, my pageViewController has 3 child viewcontrollers. First viewcontroller is fine, but when I slide to the next one, the whole view is incorrectly offset to the top (~20 pixel, I guess), but will return to normal after my finger is off the screen.
I stayed up all night looking for solution for this but still no luck finding one.
Then suddenly I came up with this crazy idea:
[pageViewController setViewControllers:@[listViewControllers[1]] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:^(BOOL finished) {
}];
[pageViewController setViewControllers:@[listViewControllers[0]] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:^(BOOL finished) {
}];
My listViewControllers has 3 child viewcontrollers. The one at index 0 has problem, so I firstly set it as root of pageviewcontroller, and right after that set it back to the first view controller (as I expected).
Voila, it worked!
Hope it helps!