Laying out & sizing of subviews in a UIViewController

49,354

Solution 1

autoresizesSubviews should be set on your parent view, while autoresizingMask should be set on the child views - this is the mistake I made so you could, too.

In loadView you should size your subviews to fit whatever size of parent view is at the moment, and then later on when parent view is resized from 460 to 367 pixels your sub-views will be resized as well, according to your mask settings above.

If that fails, there is nothing wrong in setting the view size within viewWillAppear - the performance impact of doing it every time is negligible.

If nothing else works, there is always layoutSubviews: - there you could do manual layout if you have to, it's invoked when system believes layout may have to change. there is also setNeedsLayout: that I sometimes invoke from viewWillRotate:/viewDidRotate: etc. But really this shouldn't be needed and autoresize should be good enough.

EDIT: Yes, to implement custom layout logic in layoutSubviews as I mention above one would need to subclass UIView.

Solution 2

You can do your layout logic inside the viewWillLayoutSubviews of the UIViewController.

-(void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];
    // Your layout logic here
}

DOC: Called just before the view controller's view's layoutSubviews method is invoked. Subclasses can implement as necessary. The default is a nop.

Share:
49,354
Michael Waterfall
Author by

Michael Waterfall

Updated on July 09, 2022

Comments

  • Michael Waterfall
    Michael Waterfall almost 2 years

    I have an app with with a UITabController and each tab is a UINavigationController. The root of one of my UINavigationControllers is a UIViewController.

    Inside that view controller's view, I want to layout some subviews, but I'm confused as to where & how to lay them out in a way that will be resolution independent (i.e. not hardcode values such as 320px, 480px, 44px, etc.).

    When the view is fully loaded and presented on a vertical iPhone, it's height will be 367px = 480 - 20 (status bar) - 44 (nav bar) - 49 (tab bar).

    Inside the view controller, I currently create all my subviews within the viewDidLoad method. However, it appears that within this method, the view's current height is 460px (self.view.bounds.size.height). So when setting up my subviews, I cannot properly calculate the sizes of anything.

    Within the viewWillAppear: method, the view does know it's proper size, but that would mean setting & calculating the subview's frames every time the view will appear (e.g. tab changes or popping from child view controllers on the navigation stack.

    Is the only way to do this properly to layout in viewWillAppear:?

    I have tried using the autoresizing properties (parent's autoresizesSubviews & autoresizingMask) but they don't seem to work at all!? Do these only take effect once the view is all setup and then it is resized (manually / orientation change?).

    I'd be grateful if someone could let me know why the autoresizing isn't working, and how best to lay things out by not hardcoding any sizes.

  • casademora
    casademora about 13 years
    Quick clarification, UIViewController does not have, nor call layoutSubviews. This is a method on UIView. You can, however, just make a method named layoutSubviews and call that from viewWillAppear:
  • DougW
    DougW almost 13 years
    There's no "loadViews" either. I think you mean "viewDidLoad", in which case it's worth mentioning to release those views in viewDidUnload as well.
  • Mattias Wadman
    Mattias Wadman over 12 years
    There is a loadView method but viewDidLoad is usually the most convinient place to add subviews
  • titaniumdecoy
    titaniumdecoy over 12 years
    "But really this shouldn't be needed and autoresize should be good enough" There are many situations where autoresizing masks are insufficient: for instance, a view with 3 equally divided subviews from top to bottom.
  • Chase
    Chase about 12 years
    For what it is worth, iOS 5.0 added two new functions viewWillLayoutSubviews and viewDidLayoutSubviews to the view controller class that may be helpful.
  • Van Du Tran
    Van Du Tran over 8 years
    any difference if I use viewDidLayoutSubviews instead?
  • Leang Socheat
    Leang Socheat over 7 years
    ViewDidLayoutSubViews is override function of UIViewController class, but I am in UITableViewCell, Have any method to instead of that override method?.
  • Leon
    Leon about 4 years
    No need to call super on viewWillLayoutSubviews() or viewDidLayoutSubviews(): "The default implementation of this method does nothing."
  • Top-Master
    Top-Master about 3 years
    The difference is that: the one with Will in name is called before any view's real-layout is done (best time to change any property used by their real-layout), while the one with Did in name may cause relayout !! (but is best place to hack or override the real-layout).