-1

I have a view in my app that is structured like so;

  • UIViewController (self)
    • UIView (self.view)
      • UIScrollView (scrollView)
        • UIView (contentView)
          • UIView (subviewA)
          • UIView (subviewB)
          • UIView (subviewC)

After reading a variety of posts on UIScrollView (see here and here), I now have a UIScrollView that looks properly, but doesn't actually scroll. I believe this is because my three subviews (subviewA, subviewB, and subviewC) are all built with AutoLayout.

My contentView has a bottom constraint of contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true

Ideally, I'd like my contentView's bottom anchor to actually be at the bottom of subviewC, but since subviewC is built with AutoLayout, it doesn't have a defined size when it is added to to contentView, and thus, the scrollView doesn't actually scroll.

Can anyone advise why my scroll does does not scroll vertically? It does appear that the subviews are all being added, but the lowest subview is well off-screen and doesn't actually allow me to scroll.

(There's a little bit more to this, such as how I'd like contentView to have a border that surrounds subviewA, subviewB, and subviewC, but I feel resolving the scroll issue will probably lead me down the right path on that).

ZbadhabitZ
  • 2,753
  • 1
  • 25
  • 45
  • 1
    What exactly is your question? – mag_zbc May 20 '19 at 15:09
  • @mag_zbc Updated for clarity. Specifically, my UIScrollView does not scroll vertically, even though all of my subviews are being added. I suspect this is due to the subviews not having a physical size as they are all built with autolayout. – ZbadhabitZ May 20 '19 at 15:16
  • Autolayout is perfectly fine to use in scroll view contents, as long as its done in such a way that the scroll view can calculate its content's height precisely. See my answer below. – NRitH May 20 '19 at 15:25
  • What do you have in subviewA, subviewB and subviewC? – RajeshKumar R May 20 '19 at 15:39
  • @RajeshKumarR - They are all a variety of components; UILabels, UIViews, UITextField, etc. They do have defined constants in terms of their placement and size, but the views themselves (subviewA, subviewB, subviewC) do not have defined sizes. – ZbadhabitZ May 20 '19 at 15:48

2 Answers2

1

A scroll view has to be able to calculate the size of its contents, so yes, your contentView's top constraint should match subviewA's top, and contentView's bottom should match subviewC's bottom. It's perfectly fine that all the subviews use constraints, as long as the subviews' tops and bottoms are constrained.

Once your contentView is constrained to its subviews, constrain all 4 of its edges to the scrollView's edges. (If you don't want it to scroll horizontally, then also constrain the contentView's width to be equal to the scrollView's.)

enter image description here

NRitH
  • 13,441
  • 4
  • 41
  • 44
  • I'm struggling to understand how I can add `subviewC` to `contentView` and have it pinned to the bottom of `contentView` when I actually want the bottom of `contentView` pinned to the bottom of `subviewC`. How do I force `contentView`'s bottom anchor to be the bottom of `subviewC` when `subviewC` is its child? PS Thank you for the screenshot! – ZbadhabitZ May 20 '19 at 15:45
  • `subviewC` does not have to have an explicit height constraint; it can be a `UILabel` with `0` lines (meaning it can have _any_ number of lines, which is what I have in my example screenshot). Of course, it _can_ have an explicit height if it's a `UIView` or other kind of view that doesn't have a "natural" height. – NRitH May 20 '19 at 15:50
  • "How do I force contentView's bottom anchor to be the bottom of subviewC when subviewC is its child?" I don't understand why this is a problem--just control-drag from `subviewC` to `contentView`, and select the bottom constraint. – NRitH May 20 '19 at 15:51
  • Wouldn't this make the bottom constraint of `subviewC` equal to that of `contentView`'s bottom constraint? Since `contentView` was added first, and its bottom constraint is equal that of `scrollView`, I guess I'm confused how pinning the bottom of `subviewC` will somehow make contentView taller (which seems to be why the scroll view isn't scrolling). – ZbadhabitZ May 20 '19 at 16:35
  • I think my confusion is coming from; if I add subviews to contentView, doesn't contentView *already* have to have its constraints set? How can I add subviewA to contentView without defining the constraints of contentView already? – ZbadhabitZ May 20 '19 at 22:31
  • Ah. Putting a view inside another one merely indicates that one is inside another one. *Constraints* are how you specify *where* a child view is positioned in its parent and relative to its sibling views in the same parent. That’s what auto layout is. – NRitH May 20 '19 at 22:37
  • Last question; lets say I want subviewA to indeed match the top constraint of contentView, but I want its leading anchor to be 20 points inset from contentView's leading anchor. Since contentView has no constraints set (yet), how would I say `subviewA.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20.0).isActive = true` when contentView's leading anchor hasn't been defined yet. – ZbadhabitZ May 20 '19 at 22:39
  • All views have leading, trailing, top, and bottom anchors by default. In the case of insets, though, you're talking about a view's layout margins. By default, a view's margins are 8 points from each edge. In my screen cap, you can see that many of the constraints are relative to margins. Instead of setting an anchor to an edge and giving it a value like `20.0`, it's better to set custom margins and then constrain your subview to the parent view's margins. – NRitH May 20 '19 at 23:31
0

For scrollview add Top, Leading, Trailing, Bottom constraints to its superview with 0 constant.

For ContentView add Top, Leading, Trailing, Bottom constraints to its superview scrollview with 0 constant. And add equal width to the scrollview, then add equal height to the scrollview with priority 999.

Now add Top, Leading, Trailing, Bottom constraints for the subviewA, subviewB, subviewC views.

Then add Top, Leading, Trailing, Bottom, height constraints to the subviews of subviewA, subviewB, subviewC views.

RajeshKumar R
  • 15,445
  • 2
  • 38
  • 70