NSView's autoresizing behavior

EightyEight picture EightyEight · Jun 9, 2009 · Viewed 19.1k times · Source

I need to understand how NSView autoresizes it's views. I've set everything up in IB and my subviews resize nicely (when I resize my window around with a mouse). However, if I do [myMainView setFrame:] with my new frame rect, nothing happens. All of my sub-views are still the original size (even though the main view has the correct dimensions). Child's resizeWithOldSuperviewSize: gets called, but it's still not appropriately sized.

I have a screen-full of cocoa elements on screen (screen #1), label, image, video. There's a well-defined layout for these elements. I've setup autoresizing behavior via Interface Builder that works very well. Resizing the main window resizes the elements in a satisfying manner.

Now, the user clicks the "next" button, whereupon a second screenfull of elements (screen #2) is to be drawn. My layouts are built based on a canonical screensize (say, 800x600). But now the window is larger (or smaller) because it was resized in screen #1. So the elements are now only taking a small area in the window, instead of being appropriately sized to fill the available space. I want to scale these elements.

Am I misunderstanding how autoresizing works? How can I trigger the autoresize machinery underneath NSView manually?

There are two things I can do:

  1. Manually resize the elements based on the current screen size relative to original size. This option is not my favorite because seemingly, I'm forced to rewrite the code that's already working in NSView (the autoresizing behavior
  2. My second option is to invoke the aforementioned NSView's autoresizing magic. Documentation implies that [NSView setFrame:] will do that for me. What I've tried was, resize my content view to the original screensize (800x600), render my elements and then resize it to the current window size. Conceptually, is it not identical to manually resizing the window? It appears not to be. Again, this option is preferable because it minimizes the amount of code that has te be written and maintained.

Answer

Nikolai Ruhe picture Nikolai Ruhe · Jun 16, 2009

This code

NSView* superView = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
NSView* subView   = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
[superView addSubview:subView];

[superView setAutoresizesSubviews:YES];
[subView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];

NSLog(@"subview's frame before resizing: %@", NSStringFromRect([subView frame]));
[superView setFrame:NSMakeRect(0, 0, 200, 100)];
NSLog(@"subview's frame after  resizing: %@", NSStringFromRect([subView frame]));

does give the expected result:

[...] subview's frame before resizing: {{0, 0}, {100, 100}}
[...] subview's frame after  resizing: {{0, 0}, {200, 100}}

Your problem is elsewhere. I expect that one of your container views is not a part of the view hierarchy of the window at the time when the resize occurs.

A good solution for your problem might be the use an NSTabView without tabs, because then all your views are at all times in the window (possibly hidden) and the tabview takes care of the resizing.

Another solution is to put several views on top of each other and use setHidden: to show only one.