I have a table view controller wrapped in a navigation controller. The navigation controller seems to automatically apply the correct content inset to the table view controller when it is presented via presentViewController:animated:completion:
. (Can anyone explain to me how this works exactly?)
However, as soon as I wrap the combination in a custom container view controller and present that instead, the topmost part of the table view content is hidden behind the navigation bar. Is there anything I can do in order to preserve the automatic content inset behaviour in this configuration? Do I have to "pass through" something in the container view controller for this to work correctly?
I'd like to avoid having to adjust the content inset manually or via Auto Layout as I want to continue supporting iOS 5.
I've had a similar problem. So on iOS 7, there is a new property on UIViewController
called automaticallyAdjustsScrollViewInsets
. By default, this is set to YES
. When your view hierarchy is in any way more complicated than a scroll/table view inside a navigation or tab bar controller, this property didn't seem to work for me.
What I did was this: I created a base view controller class that all my other view controllers inherit from. That view controller then takes care of explicitly setting the insets:
Header:
#import <UIKit/UIKit.h>
@interface SPWKBaseCollectionViewController : UICollectionViewController
@end
Implementation:
#import "SPWKBaseCollectionViewController.h"
@implementation SPWKBaseCollectionViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self updateContentInsetsForInterfaceOrientation:self.interfaceOrientation];
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[self updateContentInsetsForInterfaceOrientation:toInterfaceOrientation];
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
- (void)updateContentInsetsForInterfaceOrientation:(UIInterfaceOrientation)orientation
{
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
UIEdgeInsets insets;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
insets = UIEdgeInsetsMake(64, 0, 56, 0);
} else if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
if (UIInterfaceOrientationIsPortrait(orientation)) {
insets = UIEdgeInsetsMake(64, 0, 49, 0);
} else {
insets = UIEdgeInsetsMake(52, 0, 49, 0);
}
}
self.collectionView.contentInset = insets;
self.collectionView.scrollIndicatorInsets = insets;
}
}
@end
This also works for web views:
self.webView.scrollView.contentInset = insets;
self.webView.scrollView.scrollIndicatorInsets = insets;
If there is a more elegant and yet reliable way to do this, please let me know! The hardcoded inset values smell pretty bad, but I don't really see another way when you want to keep iOS 5 compatibility.
FYI in case anyone is having a similar problem: it appears that automaticallyAdjustsScrollViewInsets
is only applied if your scrollview (or tableview/collectionview/webview) is the first view in their view controller's hierarchy.
I often add a UIImageView first in my hierarchy in order to have a background image. If you do this, you have to manually set the edge insets of the scrollview in viewDidLayoutSubviews:
- (void) viewDidLayoutSubviews {
CGFloat top = self.topLayoutGuide.length;
CGFloat bottom = self.bottomLayoutGuide.length;
UIEdgeInsets newInsets = UIEdgeInsetsMake(top, 0, bottom, 0);
self.collectionView.contentInset = newInsets;
}
Thanks to Johannes Fahrenkrug's hint, I figured out the following: automaticallyAdjustsScrollViewInsets
indeed only seems to work as advertised when the child view controller's root view is a UIScrollView
. For me, this means the following arrangement works:
Content view controller inside Navigation controller inside Custom container view controller.
While this doesn't:
Content view controller inside Custom container view controller inside Navigation controller.
The second option, however, seems more sensible from a logical point of view. The first option probably only works because the custom container view controller is used to affix a view to the bottom of the content. If I wanted to put the view between the navigation bar and the content, it wouldn't work that way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With