Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What causes Container View to keep its child view's frame to match its bounds?

I'm trying to get a better understanding of how Container Views work in the storyboard. The behaviour appears to be that the container view will force its subview to resize to fill the container.

storyboard relationships

I see no constraints that explain it, and there's no mention of what class it is. It seems like some storyboard magic.

constraints

I assume that the container view must be a subclass of UIView, and I'll have a wild guess and assume its called UIContainerView, but searching through the documentation yields only two results.

search results

So how does it work?

like image 376
bradley.ayers Avatar asked Jun 30 '13 02:06

bradley.ayers


1 Answers

The storyboard editor (Interface Builder) keeps the embedded view's frame set to the container view's bounds during editing. Thus when the storyboard is written to a file, the serialized sizes of the views are identical. This happens whether or not the storyboard has auto layout enabled.

The top-level view of each view controller in the storyboard also has its autoresizing mask set to UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight, again regardless of whether the storyboard has auto layout enabled.

If auto layout is enabled, each top-level view has its translatesAutoresizingMaskToConstraints set to YES. This is different than all of the descendants of those top-level views. All of the descendants have translatesAutoresizingMaskToConstraints set to NO.

The embedding relationship is represented as a segue of class UIStoryboardEmbedSegue. (This is a private class, not part of the public API.)

When UIStoryboardEmbedSegue receives the perform message, it loads the destination view controller's view and adds it as a subview of the container view. Then it sets the embedded view's autoresizingMask to UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight. This is redundant, since Interface Builder already set it that way in the storyboard.

Then -[UIStoryboardEmbedSegue perform] checks the embedded view's translatesAutoresizingMaskToConstraints. This is also redundant, because Interface Builder set it to YES.

If the embedded view's translatesAutoresizingMaskToConstraints is YES, perform sets the embedded view's frame to the container view's bounds. Again, redundant.

If the embedded view's translatesAutoresizingMaskToConstraints is NO, perform adds constraints H:|[childView]| and V:|[childView]|, thus forcing the embedded view to fill the container view. (Yes, it actually uses the visual format language.) This branch should not be reached.

When a view has translatesAutoresizingMaskToConstraints set to YES, auto layout automatically adds constraints of type NSAutoresizingMaskLayoutConstraint and keeps them up to date when you change the view's frame. For example, the root view of a window is made to fill the window using autoresizing constraints:

<NSAutoresizingMaskLayoutConstraint:0x7555d00 h=-&- v=-&- UIView:0x7671780.midX == UIWindow:0x7551010.midX>,
<NSAutoresizingMaskLayoutConstraint:0x7555de0 h=-&- v=-&- UIView:0x7671780.width == UIWindow:0x7551010.width>,
<NSAutoresizingMaskLayoutConstraint:0x7555eb0 h=-&- v=-&- UIView:0x7671780.midY == UIWindow:0x7551010.midY + 10>,
<NSAutoresizingMaskLayoutConstraint:0x7555ef0 h=-&- v=-&- UIView:0x7671780.height == UIWindow:0x7551010.height - 20>

So that's what “causes Container View to keep its child view's frame to match its bounds”.

I figured this out by looking at the .storyboard file (it's surprisingly readable XML), and by looking at -[UIStoryboardEmbedSegue perform] in Hopper.

As for why they have the redundant checks, I can think of a few likely reasons:

  1. IB (perhaps in pre-release versions) didn't always set up the view properties the way it does now, so the code isn't redundant when loading old storyboards.

  2. Apple has internal tools that generate storyboards differently than IB.

  3. The code is there for forward compatibility with future versions of IB that allow top-level storyboard views to have different properties.

like image 100
rob mayoff Avatar answered Nov 01 '22 00:11

rob mayoff