unspokenblabber unspokenblabber - 1 month ago 7
iOS Question

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

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?

Answer

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.