Swift UIScrollView - Correct Implementation for Only Vertical Scrolling

Mike Woelmer shows how to do this correctly with Interface Builder on the Atomic Object blog.

http://spin.atomicobject.com/2014/03/05/uiscrollview-autolayout-ios/

I also have my own code only (no storyboard implementation) on github.

https://github.com/nadthevlad/AutolayotScrollview

You don't want to set the height or width of your content or views. Instead you want to use Autolayouts pins and constraints to set how the scrollview behaves.

  1. Create your UIScrollView *scrollView.

  2. You want to create one UIView *contentView which you will put the rest of your view elements into.

    [self.view addSubview:scrollView];
    [scrollView addSubview:contentView];
    [contentView addSubview:_label1];
    [contentView addSubview:_label2];
    [contentView addSubview:_label3];
    [contentView addSubview:_label4];
    [contentView addSubview:_label5];
    [contentView addSubview:_label6];
    
  3. Pin the 4 edges of scrollView to the 4 edges of self.view

  4. Pin the top and bottom edges of contentView to the top and bottom of scrollView.

  5. This is the tricky part. To set the horizontal sizing, you want the leading (right) and trailing(left) edges of the contentView to be pinned to the leading and trailing edges self.view instead of scrollView. Even though contenView is a sub view of scrollView its horizontal constraints are going to reach outside of the scrollView and connect to self.view.

  6. Pin any other view elements to contentView as you normally would.


The trick to permitting a UIScrollView to scroll in only one direction is to make the content size of the UIScrollView for the restricted dimension the same as the size of the UIScrollView's frame in the same dimension. So in this case, scrollview.contentSize.width should equal scrollview.frame.size.width.

With that in mind, try the following:

  1. Ensure you have constraints set up in the same way as described in this answer

  2. Add the following code to your view controller:

    override func viewWillLayoutSubviews()
    {
        super.viewWillLayoutSubviews();
        self.scrollView.contentSize.height = 3000; // Or whatever you want it to be.
    }
    

Personally, I'm really not a fan of Auto Layout. If you are interested in trying this without Auto Layout - ie. just with code instead of constraints - you could turn off Auto Layout for the view controller's view and change your viewWillLayoutSubviews method to look like this:

override func viewWillLayoutSubviews()
{
    super.viewWillLayoutSubviews();

    self.scrollView.frame = self.view.bounds; // Instead of using auto layout
    self.scrollView.contentSize.height = 3000; // Or whatever you want it to be.
}

This how I always do it for scrolling vertically from storyboard with constraints :

1-drag a viewcontroller

2-drag a scrollview in the controller's main view with constraints L=0 , T =0 , T =0 and B = 0 to its superview (controller's main view).

3-drag a UIVIew into the scroll view to work as its content view with constraints L-0,T=0,T=0,B=0 to its superview(the scrollview)

  • well here its time for setting Content size of scroll view , which controls scrolling both Horizontally and vertically as follows.

4-for stoping horizontal scrolling , make content view equal width to scrollview with constraint.

5-make height of content view equal hight of controller's view , This is temporary till we fill it with scrollable content .

6-add controls in the content view till finish .

7-and the most important delete the constraint you made in point 5 of the hight of content view and instead of it make constraint from the control on bottom of content view to have bottom alignment to it . This helps in making content view hight starts from first control on top and down till last control (it is all depends on this step).

8-just run and results should be as expected , otherwise please let me know .

Hope this helps!