Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Figuring out initWithFrame:self.view.frame 20 pixel (status bar) issue once and for all

I have a simple UINavigationController. In the init method I am creating and adding a UITableView as a subview.

- (id)init {
    self = [super init];
    if (self) {
        NSLog(@"%@", NSStringFromCGRect(self.view.frame)); // {{0, 20}, {320, 460}}
        tableView = [[UITableView alloc] initWithFrame:self.view.frame];
        [self.view addSubview:tableView];
    }
    return self;
}

I find I always run into the same annoying issue when working with new projects. Added subviews end up 20 pixels below the navigation bar.

Why is it that I end up with {{0, 20}, {320, 460}} for self.view.frame? I don't want to force the CGRect frame, I'd rather set it based on the view controller's frame so I don't run into issues with dynamic frame changes (tethering, phone call, etc. where the status bar is taller).

Update: Also noticed I am getting a 460 height for the frame. That doesn't make sense either. In my case, I actually have a tab bar, so the height shouldn't that be minus the status bar, minus the uinavigationbar and minus the tab bar heights?

Thanks

like image 431
runmad Avatar asked Nov 11 '11 20:11

runmad


2 Answers

Frame of UIView takes valid arguments only when -viewWillAppear, -viewDidAppear methods are called. You should NOT rely on frame and make any calculations using it before.
Also you should NOT use (from other objects) view property of UIViewController (UItableViewController) before -viewDidLoad method is called, so you should not use view and add any controllers to it in init method, only in -loadView or (better) in -viewDidLoad. Add your subview in these methods and set its frame before appearance.
In viewController's lifecycle view can be loaded and unloaded many times (for example didReceiveMemoryWarning unloads view), view can never load at all.

like image 159
Roman Temchenko Avatar answered Nov 15 '22 18:11

Roman Temchenko


You are mixing two different coordinate systems. self.view's frame is defined in the window's coordinate system (or whatever it's parent view is). tableView's frame is defined in self.view's coordinate system.

If you want something to fill the entire view, set

subView.frame = parentView.bounds;

bounds is defined in a view's own coordinate system. frame is defined in its parent view's coordinate system. So subView.frame and parentView.bounds are the same coordinate system.

When you set subview.frame = parentView.frame, they don't end up being the same thing any more than 20 grams = 20 ounces. The main view has origin at (0, 20); the subview has origin at (0, 20), but in a different coordinate system. In the window coordinate system that's (0, 40).

like image 2
morningstar Avatar answered Nov 15 '22 20:11

morningstar