UIScrollview+autolayout seems not working in iOS8/Xcode 6 preview

autolayoutios8uiscrollview

The following steps for UIScrollView+autolayout has been working for me, but not in the iOS8/Xcode 6 preview: (using storyboard, size class enabled):

  1. add a scrollview to the root view.
  2. pin zero spaces to all edges of super view.
  3. add a UIView (contentView) to the above scrollview.
  4. pin zero spaces to all edges of the scrollview
  5. add some widgets to contentView and change the height of the contentView to 2000.

=> this contentView scrolls in iOS 7, but I cannot get the same steps working in iOS 8 preview.

Even it seems working in iOS 7, it is possible that I may not doing the right way? Any suggestions?

Best Answer

I'm surprised not to have seen more comment about this. Scroll view internal autolayout is largely broken in iOS 8 (as seeded up to the time of this writing).

EDIT This was fixed in seed 5, so this note should be ignored!

The rule is supposed to be (see https://developer.apple.com/library/prerelease/ios/technotes/tn2154/_index.html) that if the content of a scroll view (its subview or subviews) is pinned to all four bounds of the scroll view, it sets the content size.

In iOS 8, however, this fails - but in an odd way. It fails only if the constraints determining the height and width of the subviews are all absolute as opposed to intrinsic.

Thus, for example, consider the code at the bottom of that tech note, where a scroll view and a really big image view are created in code (here it is; I have corrected a small typo where an at-sign was dropped):

- (void)viewDidLoad {
    UIScrollView *scrollView;
    UIImageView *imageView;
    NSDictionary *viewsDictionary;
    // Create the scroll view and the image view.
    scrollView  = [[UIScrollView alloc] init];
    imageView = [[UIImageView alloc] init];
    // Add an image to the image view.
    [imageView setImage:[UIImage imageNamed:@"MyReallyBigImage"]];
    // Add the scroll view to our view.
    [self.view addSubview:scrollView];
    // Add the image view to the scroll view.
    [scrollView addSubview:imageView];
    // Set the translatesAutoresizingMaskIntoConstraints to NO so that the views
    // autoresizing mask is not translated into auto layout constraints.
    scrollView.translatesAutoresizingMaskIntoConstraints  = NO;
    imageView.translatesAutoresizingMaskIntoConstraints = NO;
    // Set the constraints for the scroll view and the image view.
    viewsDictionary = NSDictionaryOfVariableBindings(scrollView, imageView);
    [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]];
    [scrollView addConstraints:[NSLayoutConstraint 
        constraintsWithVisualFormat:@"H:|[imageView]|" 
        options:0 metrics: 0 views:viewsDictionary]];
    [scrollView addConstraints:[NSLayoutConstraint 
        constraintsWithVisualFormat:@"V:|[imageView]|" 
        options:0 metrics: 0 views:viewsDictionary]];
}

That code works (assuming you have a really big image), because the image view is sized by intrinsic constraints. But now change the last two lines, like this:

    [scrollView addConstraints:[NSLayoutConstraint 
        constraintsWithVisualFormat:@"H:|[imageView(1000)]|" 
        options:0 metrics: 0 views:viewsDictionary]];
    [scrollView addConstraints:[NSLayoutConstraint 
        constraintsWithVisualFormat:@"V:|[imageView(1000)]|" 
        options:0 metrics: 0 views:viewsDictionary]];

Now what you have is a scroll view that is scrollable on iOS 7 but is NOT scrollable on iOS 8. Further investigation shows that this is because the content size remains at (0,0); it does not respect the absolute width and height constraints of the content view.

Related Topic