Centered content in UIScrollView using Auto Layout

As its name suggests, the purpose of the scroll view is to present content that is larger than the visible area on the screen. The hidden content is revealed by scrolling horizontally and / or vertically using the pan gesture, which is natively supported by the UIScrollView class.

Because the content can be any size and the scroll view adapts to the content size, placing the content using Auto Layout inside the scroll view is only possible in very specific situations. Auto Layout is a constraints based system; it should be provided with the minimum set of constraints that allows it to calculate the size and relative position of the views. When the constraints are insufficient or ambiguous, Auto Layout fails to compute the frames of the views and either crashes the application at runtime, or displays the views with unexpected position or size.

In order to make Auto Layout work with the content of a scroll view, we have to use landmarks relative to fixed frame views that are higher in the view hierarchy. This creates usable constraints for the Auto Layout system.

This article studies two techniques to center the content inside a scroll view using Auto Layout. The constraints are set in Interface Builder. The Xcode sample project can be downloaded here.

Attach the scroll view’s edges

The scroll view is added as a subview of the main view; its edges are attached to the superview’s edges. The constraints are created by Ctrl + dragging between the scroll view and the superview in Interface Builder Document Outline (left side area). If Xcode insists to attach the top and bottom edges to the layout guides instead of the superview’s edges, it’s possible to use the constraint creation commands in the Editor / Pin menu:

scroll view edge constraints

These constraints force the scroll view to automatically adapt to the main view size which changes depending on the device orientation. It also gives the scroll view’s some fixed landmarks Auto Layout can rely on.

Center the content view

The content view which has to be centered inside the scroll view is given a fixed width and height because it doesn’t contain any element based on which Auto Layout could compute the intrinsic content size.

We add constraints to align the horizontal and vertical centers of the content view and its superview (the scroll view):

content view size and center constraints

You will notice that the current constraints are not enough for Auto Layout to correctly compute the content size of the scroll view (the content size enables scrolling):

ambigous constraints

We fix this issue in code, by overriding the -viewDidLayoutSubviews method in the view controller’s implementation file and setting the scroll view’s contentSize property to (roughly) the size of the main view:

The height of the scroll view’s content is slightly larger than the height of the main view to enable the bouncing effect when scrolling past the content area.

When you run the application, the content view is centered vertically and horizontally in the scroll view, and stays centered when the device changes orientation.

Use a container view

If you don’t like having the ambiguous constraints error in the Document Outline, there is another way to center the content view, which is more generic, but involves using a container view and creating more constraints.

This solution is implemented in the ContainerView.storyboard file of the sample project. It is possible to switch from one storyboard to the other from the project target settings:

switching storyboards in xcode

The scroll view is attached to the main view edges, as in the first example.
The container view is added to the scroll view and attached to its four edges. We also add a constraint to keep the container view width equal to the scroll view width (which is equal to the main view width). This removes the ambiguity related to the scroll view’s content width.

The content view is added as a subview of the container vie. It is given fixed width and height, and it is centered horizontally in the container view.
To allow Auto Layout to compute the height of the container view, we add constraints between the top and bottom edges of the container and content view. This removes the ambiguity related to the scroll view’s height.

container view auto layout constraints

If you run the application, you will see the container view is attached to the top of the scroll view, as it is supposed to be according to the constraints. To place it in the vertical center of the scroll view, we initialize the contentInset property of the scroll view to add padding at the top and bottom of the container view. Here is the complete version of the overridden -viewDidLayoutSubviews method which covers both centering solutions:

The container view bounds aren’t correct the first time -viewDidLayoutSubviews is called, so we have to trigger a second layout pass by calling -setNeedsLayout on the main view in the -viewDidAppear: method.

Conclusion

In this article we explored two different solutions to center content in a scroll view. A practical application of this technique is to easily change the position of the initially centered content using the scroll view’s contentOffset property or “setContentOffset:animated:” method.

 

Catalin Rosioru