UIScrollview Setup – XCode 11, Storyboards, Autolayout

Theres probably several hundred articles online about setting up a UIScrollView.  The thing is .. every time a new version of XCode is released, it changes, just a little bit, and unless you are aware of the changes then those older articles become just enough wrong to make them useless.  So heres an up-to-date one for the current iteration of UIScrollViews and XCode 11(.2.1 at time of writing).

To be clear, with this setup, this scrollview will allow the intrinsic content size of all the elements within the scrollview to dictate how far it scrolls.  So if you add things which dont fill the screen, then it wont scroll, but if your content does exceed the screen size, it will.  And it will all work via autolayout too.  Heres how to set it up :

First, drag your scrollview into the UIViewController in your storyboard (or xib).  Set up its autolayout as you wish to, such as :

Then drag a UIView into that UIScrollview, which will act as the content view where all our actual content will be displayed. See here how the UIView is within the UIScrollview, currently without constraints.

Now you can setup the constraints for that content UIView, using the two handy guides you can see in the image above – ContentLayoutGuide, and FrameLayoutGuide.  The UIView itself is pinned to the ContentLayoutGuide (top, bottom, leading, trailing) while the height and width of the same view is pinned to the FrameLayoutGuide.  Once done the constraints look like this :

The height constraint there has a dashed outline – thats because it has a lower priority than the rest.  This is because we are going to scroll vertically, and the intrinsic content size of the elements placed in the view will then dictate the height of this view.  Or in other words – this equal height constraint is a lower priority than the sizes of the elements within it.  This means that once the elements are in place, and extend beyond the vertical limit, then the page will scroll as we expect.  So ensure to lower the priority of that height constraint, or if scrolling horizontally, the width constraint.

 

So thats all the setup, so heres some testing to check it all works. This code adds some test images into the scrollview, with programmatic autolayout that stacks them inside the content view.  First I dragged across an IBOutlet connected to the content view so that we can add stuff to it.

There are two images, one above the other. Both are pinned to leading and trailing edges. The top one is pinned to the top of the content view, and the bottom of that first image is then pinned to the top of the second image. Then the second image (also pinned to leading and trailing) is also pinned to the bottom of the content view. Because the content view itself has a lower priority height constraint, then the height of the content view is dictated by the size of these two images on top of each other – and that adds up to 800 px, which for an iPhone 7, is enough to make them go off the bottom of the screen. Heres the code :

@IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var contentView: UIView!
    
    func testScrollview() {
        let imageView1 = UIImageView.init(image: #imageLiteral(resourceName: "landscapePlaceholder.png"))
        let imageView2 = UIImageView.init(image: #imageLiteral(resourceName: "landscapePlaceholder.png"))
        contentView.addSubview(imageView1)
        contentView.addSubview(imageView2)
        imageView1.translatesAutoresizingMaskIntoConstraints = false
        imageView2.translatesAutoresizingMaskIntoConstraints = false
        
        imageView1.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
        imageView1.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
        imageView1.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
        imageView1.heightAnchor.constraint(equalToConstant: 400.0).isActive = true
        imageView1.bottomAnchor.constraint(equalTo: imageView2.topAnchor).isActive = true
        
        imageView2.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
        imageView2.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
        imageView2.heightAnchor.constraint(equalToConstant: 400.0).isActive = true
        imageView2.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
        
        self.contentView.setNeedsLayout()
    }

 

And thats all thats required to make a properly working UIScrollview in XCode 11.  I will attempt to keep this up to date as it inevitably changes in the future.  Please comment if something is out of date.

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *