Why does UIViewController extend under UINavigationBar, while UITableViewController doesn't?

63,832

Solution 1

By default, UITableViewController's views are automatically inset in iOS7 so that they don't start below the navigation bar/status bar. This is controller by the "Adjust scroll view insets" setting on the Attributes Inspector tab of the UITableViewController in Interface Builder, or by the setAutomaticallyAdjustsScrollViewInsets: method of UIViewController.

For a UIViewController's contents, if you don't want its view's contents to extend under the top/bottom bars, you can use the Extend Edges Under Top Bars/Under Bottom Bars settings in Interface Builder. This is accessible via the edgesForExtendedLayout property.

Solution 2

Objective-C:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.edgesForExtendedLayout = UIRectEdgeNone;
 }

Swift 2:

self.edgesForExtendedLayout = UIRectEdge.None

Swift 3+:

self.edgesForExtendedLayout = []

Solution 3

@Gank's answer is correct, but the best place to do this is on the UINavigationControllerDelegate (if you have one):

func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
    viewController.edgesForExtendedLayout = UIRectEdge.None
}
Share:
63,832
unspokenblabber
Author by

unspokenblabber

Updated on July 02, 2020

Comments

  • unspokenblabber
    unspokenblabber almost 4 years

    I have UITabbarController with UINavigationController in it. I have a subclass of UIView that I assign as the view of UIViewController in the navController. This is pretty standard stuff, right? This is how I do it

    _productCategoryView = [[ProductCategoryView alloc] initWithFrame:self.view.frame];
    self.view = _productCategoryView;
    

    This view has a UITableView as subView

    _productCategoryTableView = [[UITableView alloc] initWithFrame:self.frame style:UITableViewStylePlain];
    _productCategoryTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    _productCategoryTableView.backgroundColor = [UIColor clearColor];
    [self addSubview:_productCategoryTableView];
    

    For the sake of debugging I am setting self.backgroundColor = [UIColor blueColor] on the view.

    From the above initialization of tableView one might think that the view's and table's frame is same. However when I run in iOS 7, the view's origin is set behind the UINavigationBar. This is understandable because I am setting self.navigationBar.translucent = YES; in my subclass of UINavigationController. But what I don't understand is how come the table is sitting just below the navBar? Shouldn't it also start from (0, 0) which is behind the navBar? See screenshot Scenario 1 below. Notice the blue hue behind navBar

    Scenario 1

    Now, I push another viewController on the navigation stack, simply by using [self.navigationController pushViewController.....]. Again I have a custom UIView with a tableView in it. However I also have a UILabel above this table, and again for debugging, I gave it a redColor. This time I am setting the label's origin to be almost same as the view's

    CGRect boundsInset = UIEdgeInsetsInsetRect(self.bounds, UIEdgeInsetsMake(10, 10, 10, 10));
    
    CGSize textSize = [_titleLabel.text sizeWithFont:_titleLabel.font
                                   constrainedToSize:CGSizeMake(boundsInset.size.width, MAXFLOAT)
                                       lineBreakMode:NSLineBreakByWordWrapping];
    printSize(textSize);
    _titleLabel.frame = CGRectMake(boundsInset.origin.x,
                                   boundsInset.origin.y,
                                   boundsInset.size.width,
                                   textSize.height);
    

    So, going by the logic above, the label should be visible, right? But this time it's not. This time the label is behind the navBar.

    Scenario - 2

    Notice, the red hue behind navBar.

    I would really like to align the subView below the navBar consistently. My questions are

    1. How is the tableView offset by 64pixels (height of nav + status bar in iOS 7) automatically, even though it's frame is same as the view's?

    2. Why does that not happen in the second view?