TIL by Ed

Writing up things I’ve learnt.

UIScrollView contentSize and AutoLayout Gotcha

Adopting AutoLayout at work these days and I came across this interesting gotcha recently when trying to use AutoLayout with UIScrollView. The gotcha is related to setting the contentSize of the UIScrollView

Previously (when you’re not using AutoLayout) when using UIScrollView, you would set the contentSize to indicate the size of the content you are placing within the scroll view. With AutoLayout though, it is a bit different. If you do try and set the contentSize while using constraints, you’ll end up just banging your head against the keyboard.

I wasted half an hour of my time, and the solution was not immediately obvious. There is nothing in the UIScrollView documentation that mentions that you shouldn’t set the contentSize when using AutoLayout. The answer came after being lead to https://developer.apple.com/library/ios/technotes/tn2154/_index.html.

The document mentions two approaches

  • mixed
  • pure AutoLayout

Of course we go for the pure AutoLayout approach to avoid the use of Frames (yuk). To do that we need to do the following (straight from the document)

  • Set translatesAutoresizingMaskIntoConstraints to NO on all views involved.
  • Position and size your scroll view with constraints external to the scroll view.
  • Use constraints to lay out the subviews within the scroll view, being sure that the constraints tie to all four edges of the scroll view and do not rely on the scroll view to get their size.

To rephrase the above, make sure the constraints defined for the content view is able to determine its size independent of the scroll view size. An example of this is to set the size of the content view explicitly. Also make sure the constraints defined for the content view is such that the content view will sit flush against all four edges of the scroll view. Hence constraints like the ones below will satisfy those requirements:

1
2
3
4
5
6
7
8
9
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView(600)]|"
                                                                   options:kNilOptions
                                                                   metrics:nil
                                                                     views:views]];

[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView(300)]|"
                                                                   options:kNilOptions
                                                                   metrics:nil
                                                                     views:views]];

By doing the the above, AutoLayout will calculate the contentSize required, without you needing to set it. SO DON’T SET IT when using AutoLayout. I’ve put up a example project on Github https://github.com/ehuynh/ScrollViewAutoLayoutExample to demonstrate this.

Comments