---
title: "UIScrollViews and auto layout"
slug: uiscrollviews-and-auto-layout
section: tech
date: 2015-10-02T11:05:00.000Z
canonical: https://roland.leth.ro/blog/tech/uiscrollviews-and-auto-layout
---

UIScrollViews are a different kind of beast when created with auto layout, but the basic idea is to constrain it to a fixed frame, and let the constraints of its subviews determine its `contentSize`. So let's start with that:

```swift
private lazy var scrollView: UIScrollView = {
  let sv = UIScrollView(frame: CGRect.zero)
  self.view.addSubview(sv)
  
  sv.translatesAutoresizingMaskIntoConstraints = false
  sv.alignTop("0", leading: "0", bottom: "0", trailing: "0", toView: self.view)
  
  return sv
}()
```

We have a `scrollView` that is the same size of our `view`, nothing fancy.

Let's say we have two layouts, one with 3 subviews, one with 2, at `200px` height each, spaced out by `10px`. Still nothing fancy, but the catch is that the last subview has to always be pinned to the bottom of the screen.

On devices with the screen height >= `630px`, this will be simple, because scrolling won't be needed - pin the bottom edge of the last subview to the view itself. What about the other devices?

On the first layout, the `contentSize.height` of our `scrollView` will be `3 * 200 + 3 * 10 = 630px` - when scrolled to the bottom, the last subview will be at the very bottom. All good, so far.

On the second layout, the `contentSize.height` of our `scrollView` will be `2 * 200px + 2 * 10 = 420`. 

We have to constrain the last subview's bottom edge with the `scrollView`'s bottom edge, to determine its `contentSize.height`, and, sure, we could calculate the required top space on each device / layout and modify the `constant` accordingly, but the solution is much more simple and flexible:

```swift
[...]
// Add it to the scrollView, just like the rest
scrollView.addSubview(lastSubview)

lastSubview.alignBottomEdge(withView: scrollView, predicate: "0") // 1
[...]

var lastSubviewTopConstraint: NSLayoutConstraint?
var lastSubviewBottomConstraint: NSLayoutConstraint?

if screenHeight < 630 {
  lastSubviewTopConstraint = lastSubview.constrainTopSpace(toView: secondSubview, predicate: "10@999")
  // @999 means priority 999 (we're starting in layout 1)
}

// Also constrain the bottom to the view itself
lastSubviewBottomConstraint = lastSubview.alignBottomEdge(withView: view, predicate: "0@1")

// Then just toggle their priorities:
lastSubviewTopConstraint?.priority = layoutOne ? 999 : 1 // 2
lastSubviewBottomConstraint?.priority = layoutOne ? 1 : 999 // 3
```

Even though the `scrollView` is constrained to the view's height, don't be mistaken: the `lastSubview` won't be pinned to the bottom (1); this constraint only determines the `scrollView`'s `contentSize.height`.

The bottom constraint on the `scrollView` always determines the `scrollView.contentSize.height`. In addition, the top constraint (2) determines the `lastSubview`'s position, when the high priority is set. The bottom constraint (3) on the view determines the `lastSubview`'s position, when the high priority is set.

_Throughout this post I'm making use of [FLKAutoLayout](https://github.com/floriankugler/FLKAutoLayout), a great Auto Layout library._