10

I have a navigation based application where I place my custom views in the navigation view.

First, I wanna know how to get the "navigation view"'s frame so that I can place my custom view on it properly.
Also, I sometimes hide navigation bar and want to make sure I get the frame info correctly. (not with [[UIScreen mainScreen] bounds] )

Second, in general, how do I access the superview's frame so that I can place a view accordingly?
I tried the following with no success.

-(void) loadView {
[super loadView];
UIView* myView = [[UIView alloc] initWithFrame: CGRectZero];
self.view = myView;
self.view.frame = self.view.superview.frame;
[myView release];
}

or setting the frame in layoutSubviews, but noticed layoutSubviews not getting called. I guess that's because I don't have any subviews in this particular view?

Thank you

-Edit-

with given answers, i now know that i need to set the view.frame to superview's bounds.
The problem is that i'm unable to access superview inside viewDidLoad.
I can see that superview is correctly set in viewWillAppear but not in viewDidLoad.

I found out that viewDidLoad gets called at various times, such as when pushed by pushViewController or accessing self.view
I have the following code and viewDidLoad gets called from nil == controller.view.superview.

if (nil == controller.view.superview) {
    CGRect frame = scrollView.frame;
    frame.origin.x = frame.size.width * page;
    frame.origin.y = 0;
    controller.view.frame = frame;
    [scrollView addSubview:controller.view];
}

Since I can't access superview from viewDidLoad, i can't layout the view as i previously did in viewDidLoad. This seems so inconvenient and unnecessarily complex.
Any suggestion please?

eugene
  • 39,839
  • 68
  • 255
  • 489

2 Answers2

10

The superview property is nil until your view is added as a subview somewhere. In general, you can't know what the superview will be within the loadView method.

You could use autoresizing properties, as suggested by Costique. Check out the Resizing Subviews in the official UIView docs.

You could also set the frame after the call to loadView, for example in something like this:

MyViewController *myController = [[MyViewController alloc] init];
myController.view.frame = window.bounds;
[window addSubview:myController.view];

By the way, it is generally safer to use the parent's bounds property for the frame of the subview. This is because a parent's bounds are in the same coordinate system as the subview's frame, but the parent's frame may be different. For example:

UIView *parentView = /* set up this view */;
UIView *subView = /* set up subview */;
[parentView addSubview:subView];
parentView.frame = CGRectMake(30, 50, 10, 10);
subView.frame = subView.superview.frame;  // BAD!!!
// Right now subView's offset is (30, 50) within parentView.
subView.frame = subView.superview.bounds;  // Better.
// Now subView is in the same position/size as its parent.
Tyler
  • 28,498
  • 11
  • 90
  • 106
  • Thanks, I thought I could do self.view.frame = self.view.superview.bounds; in my viewDidLoad(). But I noticed I am creating my view inside loadView but I haven't actually done anything to add it to superview via addSubview or anything. So the code doesn't do anything. Weird, I was able to see the view without adding it to parent view previously. How do I add my view (which was created in loadView) to parent view? – eugene Nov 09 '10 at 06:30
  • sorry I messed up reading my own code. I guess it was added when doing initWithRootViewController of UINavigationController – eugene Nov 09 '10 at 06:56
7

Just set the autoresizing mask and the navigation controller will do the rest:

myView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
Costique
  • 23,712
  • 4
  • 76
  • 79
  • ah thanks, it would work normally I guess. But I have a scroll view as one of myView. setting autoresizingMask to scrollview would not work I suppose? – eugene Nov 09 '10 at 06:04
  • Why not? UIScrollView is just a specialized UIView which manipulates its bounds origin for scrolling. The only thing I do differently is that I initialize UIViews with [UIScreen mainScreen].applicationFrame rather than CGRectZero, but I don't think it matters at all. – Costique Nov 09 '10 at 07:35
  • I've tried your suggestion. but in my viewDidLoad(), [self.view bounds] (to layout subviews) returns (0,0,0,0). did I mess up somewhere? Do you get correct [self.view bounds] inside viewDidLoad? – eugene Nov 09 '10 at 12:11
  • 1
    If I recall correctly, viewDidLoad is sent before the view is added to the navigation controller's view hierarchy, immediately after loadView. It should be added to a superview by the time viewDidAppear: is sent. So if you need to calculate some geometry, Apple suggests you set the initial view frame to [UIScreen mainScreen].applicationFrame. And by the way, you shouldn't send [super loadView] if you set the view property. – Costique Nov 09 '10 at 12:31