Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIViewController viewDidLoad incorrect width/height

Everybody knows that you can't trust the frame size on a UIViewController init/viewDidLoad method; this:

- (void)viewDidLoad: {
     NSLog(@"%d", self.view.frame.size.width);
}

will print wrong sizes in many occasions (in particular it's pretty much broken in landscape mode)

This will actually return always corrected results so it's good to layout the subviews:

- (void)viewWillAppear: {
     NSLog(@"%d", self.view.frame.size.width);
}

The problem is that viewWillAppears gets called every time the view appears, so it's not suitable to alloc or add subviews. So you end up declaring every single view in the interface and you end up with huge header files that I don't like at all since most of the items don't need any more manipulations after the initial setup.

So question one is: Is there a better way to handle subviews positioning?

Question two is very related, let's say I have a subclass of UIView including various others subviews. I declare it inside my interface, and i alloc/init it in my init/viewDidLoad method.

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    ...
    menu = [[SNKSlidingMenu alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
    ...
}

As we already know we now need to reposition it in viewWillAppear to get a more accurate reading

- (void)viewWillAppear:(BOOL)animated{
    ....
    menu.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
    ....
 }

The problem is that of course all the subviews needs to be repositioned as well. This is done by the layoutSubviews function that get called automatically, but we got the same problem: All the subviews need to be declared inside the interface of the SNKSlidingMenu class.. Is there a way around this?

Thanks.

like image 358
ksn Avatar asked May 28 '13 16:05

ksn


2 Answers

If you are targetting iOS 5.0 or better you can use viewWillLayoutSubviews and viewDidLayoutSubviews to make changes.

As for your second question, if you need access to an instance variable in other method than init, you need to keep it around, I don't see a problem with it.

You can, however, try to use Auto Layouts and set up rules between the subviews so it's automatically laid out for you without the need to keep a reference.

like image 133
pgb Avatar answered Nov 09 '22 10:11

pgb


viewWillLayoutSubviews and viewDidLayoutSubviews can resolve this problem.
But the two methed would be performed more times. this is my code to get correct self.view.frame.

- (void)viewDidLoad {
  [super viewDidLoad];  
  ...  
  dispatch_async(dispatch_get_main_queue(), ^{  
   // init you view and set it`s frame. this can get correct frame.   
   ...  
  }  
  ...  
}
like image 28
Huang Huang Avatar answered Nov 09 '22 10:11

Huang Huang