The AutoLayout UIScrollView content does not resize in rotation (including the sample project)

advertisements

I'm trying to wrap my head around AutoLayout works and I think I understand most of it except for UIScrollViews. When I add those views to a project, they refuse to expand the dimensions of the screen. They will appear fine in the iPhone vertical view but when rotated, they will not expand. Also, when you launch the project in the iPad simulator, the UIScrollView screens will not expand to the dimensions of the iPad. The actual UIScrollView expands but it's content does not expand.

I've followed the instructions from Apple (https://developer.apple.com/library/ios/technotes/tn2154/_index.html) and while that fixed my dynamic content height issue, it has not solved the issue where the UIScrollView content does not expand to match the width of the screen. I've read that I need to pin the inner child of the scrollview to the right edge of the UIView but that seems like a bit of a hack and that also seems to contradiction the above Apple documentation.

Here's what I have:

  • UI and therefore the main View is created in a nib.
  • The view is a regular UIView. Not a UIScrollView
  • UIScrollView is created and added in viewDidLoad
  • All dynamic content is drawn in the nib and is stored in a separate UIView name contentView
  • contentView is added to scrollView in viewDidLoad
  • Constraints are added in viewDidLoad that pins the scrollView and contentView to the edges of their superViews.

Code from viewDidLoad:

- (void)viewDidLoad
{
  [super viewDidLoad];

  UIView* contentView = self.contentView;

  UIScrollView * scrollView = [[UIScrollView alloc] init];

  [self.view addSubview:scrollView];
  [scrollView addSubview:contentView];

  //remove auto contraints
  [scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];
  [contentView setTranslatesAutoresizingMaskIntoConstraints:NO];

  // Set the constraints for the scroll view and the image view.
  NSDictionary* viewsDictionary = NSDictionaryOfVariableBindings(scrollView, contentView);
  [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics: nil views:@{@"scrollView":scrollView}]];
  [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics: nil views:@{@"scrollView":scrollView}]];
  [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|" options:0 metrics: nil views:viewsDictionary]];
  [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|" options:0 metrics: nil views:viewsDictionary]];

}

You can download the sample project from here: TestAutoLayout.zip

Does anyone have any idea why the scrollView content does not expand to the width of self.view despite the adding of the constraints?


As explained in this answer: https://stackoverflow.com/a/16843937/950953, linking the contentView to the width of main view seems to be the only thing that works.

I modified the constraint code from above with this section of code and the screen now lays out correctly.

UIView *mainView = self.view;

// Set the constraints for the scroll view and the image view.
NSDictionary* viewsDictionary = NSDictionaryOfVariableBindings(scrollView, contentView, mainView);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|" options:0 metrics: 0 views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|" options:0 metrics: 0 views:viewsDictionary]];

//hack to tie contentView width to the width of the screen
[mainView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[contentView(==mainView)]" options:0 metrics:0 views:viewsDictionary]];

If anyone can find a proper solution, please post it.