topLayoutGuide in child view controller
While this answer might be correct, I still found myself having to travel the containment tree up to find the right parent view controller and get what you describe as the "real topLayoutGuide
". This way I can manually implement automaticallyAdjustsScrollViewInsets
.
This is how I'm doing it:
In my table view controller (a subclass of UIViewController
actually), I have this:
- (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; _tableView.frame = self.view.bounds; const UIEdgeInsets insets = (self.automaticallyAdjustsScrollViewInsets) ? UIEdgeInsetsMake(self.ms_navigationBarTopLayoutGuide.length, 0.0, self.ms_navigationBarBottomLayoutGuide.length, 0.0) : UIEdgeInsetsZero; _tableView.contentInset = _tableView.scrollIndicatorInsets = insets;}
Notice the category methods in UIViewController
, this is how I implemented them:
@implementation UIViewController (MSLayoutSupport)- (id<UILayoutSupport>)ms_navigationBarTopLayoutGuide { if (self.parentViewController && ![self.parentViewController isKindOfClass:UINavigationController.class]) { return self.parentViewController.ms_navigationBarTopLayoutGuide; } else { return self.topLayoutGuide; }}- (id<UILayoutSupport>)ms_navigationBarBottomLayoutGuide { if (self.parentViewController && ![self.parentViewController isKindOfClass:UINavigationController.class]) { return self.parentViewController.ms_navigationBarBottomLayoutGuide; } else { return self.bottomLayoutGuide; }}@end
Hope this helps :)
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];}