Why does UIViewController almost always require layoutSubViews?

3.2k Views Asked by At

Before iOS7, I whatever CGRect I define to a UIView's frame, it was working.

For example:

imageView.frame=CGRectMake(20,20,80,80);

was perfectly leaving 20 x 20 margin at the top left of the screen.

Interestingly if I add another UIView with:

nextView.frame=CGRectMake(imageView.frame.origin.x+imageView.frame.size.width+10,20,100,100);

nextView appears near imageView, so It somehow accepts X parameter for the second view but it does not accept the Y coordinate for that view too.

Now, I have to use viewWillLayoutSubviews to arrange all of those coordinates. Otherwise, for example, frame for imageView becomes 0,0,80,80 automatically. (it snaps to top-left)

I am not using any nibs and I also even tried creating UIViewController with custom initWithFrame method to set the CGRect before loadView or viewDidLoad but it doesn't matter.

Is there something that automatically overrides x,y of Views? Like an auto-layout system etc? I don't want to use viewWillLayoutSubviews method to rearrange all of those coordinates.

What is happening here?

Update 1

- (id)initWithFrame:(CGRect) frame
{
    self = [super init];
    if (self) {

        self.frame=frame; //frame is custom variable to hold it until loadViews method

    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
}
-(void)loadView{
    UIView *view=[[UIView alloc]initWithFrame:_frame];

    view.backgroundColor=[UIColor blackColor];
    self.imageView=[[UIImageView alloc]initWithFrame:CGRectMake(20, 20, 80,80)];
    self.imageView.backgroundColor=[UIColor redColor];

    [view addSubview:_imageView];

    self.textView=[[UITextView alloc]initWithFrame:CGRectMake(self.imageView.frame.origin.x+self.imageView.frame.size.width+10, self.imageView.frame.origin.y, view.frame.size.width-20-(self.imageView.frame.origin.x+self.imageView.frame.size.width+10), view.frame.size.height-self.imageView.frame.origin.y-20)];
    [view addSubview:_textView];

    self.view=view;
}

I tried similar code in initWithFrame and also in viewDidLoad. Result was the same.

Update 2

I have mistakenly written "layoutSubviews" instead of "viewWillLayoutSubviews" in the question, so I fixed it: I am not creating a custom UIView but UIViewController, so it had to be "viewWillLayoutSubviews" in the question.

2

There are 2 best solutions below

3
On

My guess is that you are reversing the status bar as the top left point, but in iOS7 the status is transparent is the top point is the actual top left of the screen.

You can change your coordinates or add this to you view controller :

 if([self respondsToSelector:@selector(setEdgesForExtendedLayout:)])
    {
        [self setEdgesForExtendedLayout:UIRectEdgeNone];
    }

This will reset your top left point to the bottom of the status bar.

Any way, I believe putting your layout code in those methods:

- (void)viewWillLayoutSubviews 
- (void)viewDidLayoutSubviews
1
On

whenever a subview is added,a UIScrollView is scrolled,Frame is set for View, layoutSubViews? is called,