558

Fellow devs, I am having trouble with AutoLayout in Interface Builder (Xcode 5 / iOS 7). It's very basic and important so I think everyone should know how this properly works. If this is a bug in Xcode, it is a critical one!

So, whenever I have a view hierarchy such as this I run into trouble:

>UIViewController
>> UIView
>>>UIScrollView
>>>>UILabel (or any other comparable UIKit Element)

The UIScrollView has solid constraints, e.g., 50 px from every side (no problem). Then I add a Top Space constraint to the UILabel (no problem) (and I can even pin height / width of the label, changes nothing, but should be unneccessary due to the Label's intrinsic size)

The trouble starts when I add a trailing constraint to the UILabel:

E.g., Trailing Space to: Superview Equals: 25

Now two warnings occur - and I don't understand why:

A) Scrollable Content Size Ambiguity (Scroll View has ambiguous scrollable content height/width)

B) Misplaced Views (Label Expected: x= -67 Actual: x= 207

I did this minimal example in a freshly new project which you can download and I attached a screenshot. As you can see, Interface Builder expects the Label to sit outside of the UIScrollView's boundary (the orange dashed rectangle). Updating the Label's frame with the Resolve Issues Tool moves it right there.

Please note: If you replace the UIScrollView with a UIView, the behaviour is as expected (the Label's frame is correct and according to the constraint). So there seems to either be an issue with UIScrollView or I am missing out on something important.

When I run the App without updating the Label's frame as suggested by IB it is positioned just fine, exactly where it's supposed to be and the UIScrollView is scrollable. If I DO update the frame the Label is out of sight and the UIScrollView does not scroll.

Help me Obi-Wan Kenobi! Why the ambiguous layout? Why the misplaced view?

You can download the sample project here and try if you can figure out what's going on: https://github.com/Wirsing84/AutoLayoutProblem

Illustration of the problem in Interface Builder

Wirsing
  • 6,104
  • 3
  • 13
  • 13
  • 8
    Try placing the UILabel in a content view, then setting the trailing edge of the label to the content view (regular UIView). This video may help you greatly: http://www.youtube.com/watch?v=PgeNPRBrB18&feature=youtu.be – erdekhayser Sep 27 '13 at 00:39
  • 1
    Great video but it didn't fix the warnings for me. :( – Mr Rogers Sep 30 '13 at 15:48
  • Thank you very much for the video - there was (rather surprisingly) quite a lot I learned from it! However, when I combine the knowledge of the video with http://stackoverflow.com/questions/18953617/wrong-trailing-space-constraints-for-children-of-uiscrollview?rq=1 I can fix the warnings. The question that remains is: How to make the scrollView's contentView size only as large as necessary? – Wirsing Oct 01 '13 at 15:58
  • Take a look at [this](https://www.youtube.com/watch?v=4oCWxHLBQ-A) video. It shows how to use UIScrollLayout and autolayout with XCode 5 / iOS 7 . – jaxvy Feb 12 '14 at 20:53
  • My suggestion is don't use `UIScrollView` directly. Instead use `UICollectionView` or `UITableView` as much as possible, mostly every thing is possible with these element and its also give simplicity, readability and reusability!!! – SPatel Jun 30 '18 at 05:36
  • In addition to top space and trailing space, add leading space and bottom space as well. – Ting Yi Shih Sep 25 '18 at 13:50
  • I just set Ambiguity->Never Verify in the Size Inspector and it works without adding UIView as a subview (which broke some things for me, actually). I usually do the rest in code. Found no issues with that so far. – Paweł Pela Nov 04 '18 at 13:55
  • [_At any given time the layout engine needs to be able to calculate the **size** of contents (not frame) of the scrollView. Hence it's the only view that needs 6 constraints not 4. For any other view having more than 4 required constraints will cause a conflict. But again not for scrollviews._](https://stackoverflow.com/a/63789184/5175709) – Honey Sep 08 '20 at 07:36
  • Make sure you've read (and understand) Apple TN2154: "UIScrollView And Autolayout", which explains the steps required – ATV Dec 16 '20 at 07:35

34 Answers34

1155

So I just sorted out in this way:

  1. Inside the UIScrollView add a UIView (we can call that contentView);

  2. In this contentView, set top, bottom, left and right margins to 0 (of course from the scrollView which is the superView); Set also align center horizontally and vertically;

Finished.

Now you can add all your views in that contentView, and the contentSize of the scrollView will be automatically resized according with the contentView.

Update:

Some special case is covered by this video posted by @Sergio in the comments below.

Matteo Gobbi
  • 16,670
  • 3
  • 24
  • 38
  • 36
    Almost perfect, except that the scrollview can no longer guess the length of your content and resize accordingly it's contentSize to fit the objects inside. I have a tableview inside the contentView whose height changes (via constraint) and the scrollview doesn't allow me to scroll. – CyberMew May 11 '15 at 07:13
  • I removed Center X and Y, which resulted in me getting ambiguity warning for `UIScrollView`. I made sure my object (`UITableView`) inside has constraint pinning to all 4 sides. My `UITableView`'s height is set dynamically. Now, I just pin `contentView` to `UIScrollView` and the warning is gone. – CyberMew May 11 '15 at 08:10
  • Do you have a tableview in a scrollview? Maybe could be this your problem, cause this approach really works. Also: why do you need table view in a scroll view? – Matteo Gobbi May 12 '15 at 10:01
  • One more note,do set `alwaysBounceVertical` or `alwaysBounceHorizontal` to true if the content is smaller than bounds if you want to scroll no matter what content size currently it is. – tounaobun Jul 08 '15 at 05:22
  • still can't get it to scroll, even when setting it onLoad, like I did here: http://stackoverflow.com/questions/10518790/how-to-set-content-size-of-uiscrollview-dynamically/31296655#31296655 Did exactly as you described :( – CularBytes Jul 08 '15 at 16:04
  • dude, in ur code I can just see u are using frames..no constraints. – Matteo Gobbi Jul 08 '15 at 23:13
  • 28
    Maybe this [video](https://www.youtube.com/watch?v=UnQsFlMGDsI) can help to overcome all remaining issues. – Sergio Jul 11 '15 at 18:57
  • 47
    this doesnt make it scroll tho. – dorian Aug 06 '15 at 12:46
  • 1
    @Matteo Gobbi: What do you mean by "(of course from the scrollView which is the superView)" ? Do I have to "set top, bottom, left and right margins to 0" for the contentView or the scrollView ? – salocinx Sep 01 '15 at 08:30
  • 1
    @salocinx an autolayout constraint requires 2 views between which to set the constraints. The contentView, has to be 0pt from the top, 0 from the bottom, and so on. That "top" is not the top of the screen..but the top of the superview (which is the scollView). – Matteo Gobbi Sep 02 '15 at 13:26
  • 2
    @MatteoGobbi That was it ! It did the trick ! Was struggling with this kind of problems of scrollView autoLayout madness for 2 days.... Thank u dude !!! – polo987 Dec 09 '15 at 16:14
  • 1
    i corrected it in my storyboard 2 months back. I forgot again. Lol and came back to same anwers :) thanks bro – khunshan Dec 10 '15 at 14:42
  • 1
    ahahah guys I didn't think to create all this XD my colleagues in my team end up in my answer constantly and I work next to them. So funny! XD cc/ @khunshan – Matteo Gobbi Dec 11 '15 at 00:17
  • 3
    Does not work. The view does not scroll so the contentSize is not automatically resized. Why so much up votes for a tip, which basically just removes the errors in IB, but prevents scrolling? Or am I missing something, which is not said? – Tapani Dec 14 '15 at 21:13
  • @Tapani probably u are missing something. There are special cases which can be solved the video I mentioned in my post. Maybe u are in one of those. Watch the video. – Matteo Gobbi Dec 15 '15 at 10:04
  • I set the contentView height to a fixed value and then the scrolling works if the screen is smaller than the contentView. In the video they instructed to set the contentView dimensions to equal the root view's dimensions. I don't understand how that would set the contentView's dimensions correctly when the root view is smaller than the contentView. – Tapani Dec 15 '15 at 12:33
  • 2
    THIS ANSWER IS WRONG. SEE THE VIDEO LINK IN ANSWER – khunshan Dec 15 '15 at 15:46
  • The ScrollView is the element which is larger than its superview. Therefore its height is set by its contents or directly in a height setting. The width can be set to the superview in which case there will be no lateral scrolling. – user462990 Feb 18 '16 at 15:37
  • 63
    For anyone facing problem with ScrollView being not scrollable, setting contentView's bottom and align center vertically constrains with low priority did the trick for me! – jimmy0251 May 13 '16 at 08:49
  • 1
    Dude where are you, I want to hug you right now, I was struggling with this since 2 days, bro you saved me. BTW in my case everything was same as mentioned by you except one thing i.e. align center horizontally and vertically. Can you please explain what is the need of center alignment? – ViruMax Jul 05 '16 at 11:22
  • 1
    @dorian and anyone else who ran into the issue of: constraint conflicts resolved, scrollView not scrolling... try removing the center.x and center.y on the contentView and instead set the contentView height and width to equal the scrollview's. set the equal heights constraint to a 250 priority – nitsyrk Sep 28 '16 at 14:43
  • 1
    If your scene has a navigation bar, do as indicated above. But you are not done because your content view will have a blank space at the top, under the navigation bar, as high as the navigation bar again. To fix that, [read this](http://stackoverflow.com/questions/18967859/ios7-uiscrollview-offset-in-uinavigationcontroller), in particular the answers by streem and Myxtic. – Jerry Krinock Dec 04 '16 at 04:48
  • Isn't centering superfluous? – Iulian Onofrei Mar 28 '17 at 08:57
  • 1
    @Sergio, Why is the `'Content View'.height == View.height` necessary? Shouldn't its height be equal to its subviews height? – Iulian Onofrei Mar 28 '17 at 09:04
  • 1
    The video @Sergio posted looked stupid at first, but I have to admit it made it for me. I think the point here is that you have to pin your real content (a uilabel or whatever) to the bottom of the contentView, and the contentView should have width and size equal to the parent of the scrollview - then the height constraint should have low priority if we want scrolling vertical. – Jonny Apr 14 '17 at 02:25
  • 1
    This is one of the finest stack overflow answers I have come across. You sir, are a gentleman and a scholar. – Mike Simz Dec 07 '17 at 19:33
  • 1
    ^^ This is one of the best comment I got on StackOverflow XD Thank you, happy to help! :) – Matteo Gobbi Dec 11 '17 at 23:38
  • 1
    I only needed to follow steps 1 through 4 of [this answer](https://stackoverflow.com/a/45294116/736809), because the above and the video did not help me. Xcode 9, iOS 11. – Jimbo Mar 11 '18 at 21:11
  • 1
    thats work for a while, but i am not able to touch buttons in the bottom – mohammad alabid May 12 '18 at 21:30
  • 1
    Just wanted to say I was still having trouble until I pinned the bottom-most element of the content view (in my case a UILabel) to the bottom of the content view with Relation = "Greater Than or Equal". Scrolling worked after this. – aufty May 29 '18 at 21:00
  • If anyone is having issues with it not scrolling the whole content size this video helped -> https://www.youtube.com/watch?v=nfHBCQ3c4Mg. (Basically after following the above procedure: 1. Freeform ViewController in storyboard. Change hight until it hugs your content. 2. Set the lowest element to the bottom of contentView. – mikemike396 Nov 16 '18 at 21:34
  • Setting the bottom constraint of the last element in the content view is the key for the scrollview to make it scrollable... Irrespective of all the steps followed in the answer, We need to set the bottom constraint of the last element. – Pradeep Reddy Kypa Mar 07 '19 at 19:53
  • 2
    Note that my answer is 4.5 years old and that Apple worked around this problem implementing a similar solution in their sdk a couple of years ago. Whatever solution you find today isn’t the solution that was needed when we had iOS < 10. – Matteo Gobbi Mar 10 '19 at 18:22
  • Unfortunately, does not appear to be working today. – Oscar Jul 25 '19 at 21:35
  • In my case, I was missing bottom anchor, so the compiler couldn't calculate the total content height – Andoni Da Silva Sep 09 '19 at 08:22
  • 9
    After 5 years, and after 3 hours spent trying to understand why my imageView wasn't showing up on the scrollView, I remembered my own answer here and solved the problem - which means that even working on iOS12, this answer is still valid. The key piece remains to center the view. – Matteo Gobbi Sep 20 '19 at 18:46
  • I can confirm that attached video also is valid for iOS 13 and Xcode 11 – Paweł Madej Oct 14 '19 at 10:38
  • 2
    this answer didn't work for me, almost... I have to deselect the "Content Layout Guides" in the inspector for it to work. – zumzum Jun 24 '20 at 22:39
  • One issue I had was that all of my subviews had inequality height constraints. That upsets AutoLayout and you solve it by adding another lower priority fixed height constraint that is your lower limit, as suggested here: https://stackoverflow.com/a/43949595/826946 – Andy Weinstein Sep 17 '20 at 16:57
  • Here's what finally worked for me. 1) Follow accepted answer first. 2) As @jimmy0251 says, set contentView's bottom and align center vertically constraints to low priority. 3) Set the height (highest priority) of the content view to include all your views. – kanso Apr 20 '21 at 21:01
174

Xcode 11+

The simplest way using autolayout:

  1. Add UIScrollView and pin it 0,0,0,0 to superview (or your desired size)
  2. Add UIView in ScrollView, pin it 0,0,0,0 to all 4 sides and center it horizontally and vertically.
  3. In size inspector, change bottom and align center Y priority to 250. (for horizontal scroll change trailing and align center X)
  4. Add all views that you need into this view. Don't forget to set the bottom constraint on the lowest view.
  5. Select the UIScrollView, select the size inspector and deselect Content Layout Guides.
Đorđe Nilović
  • 2,772
  • 1
  • 19
  • 20
  • 1
    I was unable to set content height of scrollview but it works. :) – Blind Ninja May 24 '18 at 06:01
  • 2
    Hint: by me it worked only, if I removed center horizontally and vertically and replacing it with equal width (scrollView + view inside scrollView) AND adding the height based on the content, which means the last element of the view need a bottom constraint. Look here for more informations: https://stackoverflow.com/a/54577278/5056173 – Sean Stayns Feb 07 '19 at 15:58
  • 1
    Sean, I'm using this literally every day and I never had a problem with this approach when it comes to vertical and horizontal scrollview scrolling. Maybe you forgot to put a bottom constraint on the lowest/last element. Without that, this will not work. – Đorđe Nilović Feb 07 '19 at 17:12
  • 12
    Point number 4 - second sentence is the big one. – Nitish May 30 '19 at 09:37
  • 2
    I'm coming from Android background so what I can say is WTF that apple is doing with the devs – Mina Farid Aug 10 '20 at 21:38
  • Well, I'd like to put in a good word for the 3rd point (changing the priorities) – Andy Weinstein Sep 17 '20 at 16:23
  • Repeating comment from above because this answer helped me too: one issue I had was that all of my subviews had inequality height constraints. That upsets AutoLayout and you solve it by adding another lower priority fixed height constraint that is your lower limit, as suggested here: https://stackoverflow.com/a/43949595/826946 – Andy Weinstein Sep 17 '20 at 16:58
  • very helpful - thanks! – dijipiji Feb 04 '21 at 23:05
101

This error took me a while to track down, initially I tried pinning the ScrollView's size but the error message clearly says "content size". I made sure everything I pinned from the top of the ScrollView was also pinned to the bottom. That way the ScrollView can calculate its content height by finding the height of all the objects & constraints. This solved the ambiguous content height, the width is pretty similar... Initially I had most things X centered in the ScrollView, but I had to also pin the objects to the side of the ScrollView. I don't like this because the iPhone6 might have a wider screen but it will remove the 'ambiguous content width' error.

self.name
  • 2,151
  • 2
  • 15
  • 17
  • 32
    Thank you for your answer! If I understand you correctly you achieve to remove the error by pinning each and every subview in the ScrollView to the top and the bottom. However, this is not necessary. You just have to make sure that there is a way to make a continuous line of constraints from the top to the bottom of the scrollview. [-X-X-X] I hope that was understandable ;> – Wirsing Oct 02 '13 at 08:38
  • 2
    How to fix the problem if the view has a variable hight? How do I set up the constraints then so that the scrollview can calculate the sizes? – hashier Oct 24 '13 at 01:38
  • @hashier I think that if the scrollview is of variable height, there is no trouble as this warning is thrown on design time, but not affects the runtime of your app. A variable height scrollview must have resized it's contentSize by code. – Frederic Yesid Peña Sánchez Oct 24 '13 at 14:17
  • According to: http://stackoverflow.com/questions/17510135/dynamic-uiview-height-with-auto-layout-in-ios-6 it is not necessary to resize the contentSize with auto layout, but I can't get it working like shown there or with updating contentSize. It just won't become scrollable: http://loessl.org/~hashier/relpub_2/DynLabel.zip I only have the mainView, scrollView, contentView, myLabel and then set all constraints as suggested. – hashier Oct 24 '13 at 15:43
  • Yup. This worked for me too. I made sure at least one child object had a constraint for leading space, trailing space, and its width. – yujean Oct 25 '13 at 05:54
  • 2
    'You just have to make sure that there is a way to make a continuous line of constraints from the top to the bottom of the scrollview' – Adam Waite Apr 09 '14 at 11:52
  • "continuous line of constraints" is EXACTLY right! From top to bottom and left to right – self.name Jun 26 '14 at 04:02
  • 3
    What helped me was making sure the scroll view was pinned to the superview and not the top or bottom layout guides. I removed the constraint for the bottom layout guide and went through the menu instead of interface builder. Editor -> Pin -> Bottom Space to Superview. – Alberto Lopez Aug 18 '14 at 17:28
  • "Initially I had most things X centered in the ScrollView." - So, how I can set all views X-centered in ScrollView for all iPhone screens at once? In this case I can't set strict constrains to the borders (because they different for all iPhones). – skywinder Oct 08 '14 at 12:50
  • @self.name it seems I found how to avoid pin view to sides. Look at my answer below. – skywinder Oct 15 '14 at 13:07
  • 2
    If you want the scrollview's width to follow the width of your phone's screen or any other element in your UI (like the containing UIView) you need to set "equal width" on it by using another element that is outside of the scrollview for measure. – Departamento B Dec 26 '14 at 15:05
  • This answer actually explains the reason for the issue and an additional 'content view' is not required to actually address the issue as explained in the accepted answer. – Raj Pawan Gumdal Sep 17 '19 at 12:04
101

Xcode 11+, Swift 5

If you are wondering why all of the answers does not work anymore, make sure that you have pinned the content view (the one you've put inside the scroll view) to Content Layout Guide of the scroll view and NOT to Frame Layout Guide.

Content view edges (leading, trailing, top, bottom) should not be pinned like leading on the image - to Frame Layout Guide

Not like this

but like this - to Content Layout Guide.

Select Content Layout Guide from dropdown

enter image description here

And then the most of the answers will work for you.

The most simple approach now is going like this:

  1. Put scroll view in the root view
  2. Pin all the sides of scroll view to the superview
  3. Take another UIView (will call it content view) and put it inside the scroll view
  4. Pin all the sides of the content view to scroll view's Content Layout Guide
  5. Pin the content view's width to be equal to scroll view's Frame Layout Guide
  6. Fix the content view height in any way you want (I used just constant height constraint in the example below)

Overall your structure in the simplest implementation will look like this

enter image description here

WantToKnow
  • 1,367
  • 2
  • 10
  • 18
63

It's answer for my self-answered question UIScrollView + Centered View + Ambigous Scrollable Content Size + many iPhone sizes.

But it fully cover your case too!

So, here is the initial state for simplest case:

  1. scrollView with 0 constraints to all edges
  2. Button centered Horizontal and Vertical with fixed Width and Height constraints
  3. And, of course - annoying warnings Has ambiguous scrollable content width and Has ambiguous scrollable content height.

1

All, that we have to do is:

  • Add 2 additional constraints, for example "0" for trailing and/or bottom space for our view (look at the example on screenshot below).

Important: you have to add trailing and/or bottom constraints. Not "leading and top" - it's not works!

2

You can check it in my example project, that demonstrating how to fix this issue.

P.S.

According logic - this action should cause "conflicting constraints". But no!

I don't know why it works and how Xcode detects which constraint is more prioritised (because I'm not set priority for these constraints explicity). I'll be thankful if someone explain, why it works in comments below.

Community
  • 1
  • 1
skywinder
  • 20,546
  • 15
  • 87
  • 122
  • Great tip! I ended up just creating a constraint to bottom edge and set priority to medium or low – Dean May 06 '15 at 03:56
  • Wow! This seriously does not make any sense but works! Thank you! The last item i have in my view i set a bottom constraint of 0, and BANG. Finally worked. – Jakob Hviid Nov 24 '15 at 14:00
51

You need to create an UIView as a subview of the UIScrollView as described below:

  • UIViewController
  • UIView 'Main View'
    • UIScrollView
      • UIView 'Container View'
        • [Your content]

The second step is to make the UIScrollView constraints. I did this with the top, bottom, leading and trailing constraints to its superView.

Next I added the constraints for the container of UIScrollView and here is where the problem begins. When you put the same constraints (top, bottom, leading and trailing) the Storyboard gives a warning message:

"Has ambiguous scrollable content width" and "Has ambiguous scrollable content height"

Continue with the same constraints above, and just add the constraints Equal Height and Equal Width to your Container View in relation to the Main View and not to your UIScrollView. In other words the Container View's constraints are tied to the UIScrollView's superview.

After that you will not have warnings in your Storyboard and you can continue adding the constraints for your subviews.

Dale K
  • 16,372
  • 12
  • 37
  • 62
Thiago Monteiro
  • 630
  • 5
  • 9
42

I had the same issue. Untick this checkbox. Since you are setting the content size in code. enter image description here

Yodagama
  • 2,244
  • 1
  • 16
  • 21
24

I finally figured this out, I hope this is easier to understand.

You can often bypass that warning by adding a base UIView to the scrollview as a "content view", as they mentioned and make it the same size as your scroll view and, on this content view, set these 6 parameters.

enter image description here

As you can see, you need 6 total parameters! Which.. under normal circumstances, you're duplicating 2 constraints but this is the way to avoid this storyboard error.

William T.
  • 12,040
  • 3
  • 52
  • 51
  • 1
    The above almost worked for me, as I'm worried about 3 different screen widths (4/5, 6, 6+) I set the content view and scroll view to have equal widths. You're right, it is a duplicate as I already told the content view to have 0 leading and ending space. – Stuart P. Nov 04 '15 at 01:07
  • 8
    You can set equal width and height constraints from content view to scroll view, instead of constant values. This will work on all resolutions. – Kumar C Jul 10 '16 at 12:59
  • I have to implement same, so can you help me that i have to set equal height and width for both content view and scroll view? – Urmi Apr 25 '17 at 14:14
  • Might be worth checking to see if you still have to do this. I set up a imageView in a scrollview recently and was able to get away with only setting the 4 constraints shown at the top to make the error disappear in Xcode 8.3 – William T. Apr 26 '17 at 04:53
  • _You definitely need to add a base UIView to the scrollview as a "content view"_ NOT TRUE. I've thought that the same. But recently I learned that there are various ways to setup a scrollView. I find it that many times the reason the scrollView is confused on what to do is because people are mixing the different approaches all at once! See [here](https://stackoverflow.com/a/51688252/5175709) for different approaches. – Honey Oct 25 '18 at 23:16
  • 1
    @Honey this was posted over 3 years ago. They've definitely improved storyboards since then. I too noticed you can get away without the content view now. I'll adjust my answer. – William T. Oct 27 '18 at 17:43
  • Your edit, is vague. Can you try a more descriptive edit? – Honey Oct 27 '18 at 18:35
16

I know I may be late, but next solution solves this kind of problems without additional code, just using storyboards:

For your content view you need to set constraints for leading/trailing/top/bottom spaces to scrollview and this will not change content view frame, like this: enter image description here

Of course you need to create additional constraints for content view so scroll view could know content size. For example set fixed height and center x.

Hope this helps.

Borzh
  • 4,450
  • 2
  • 41
  • 58
9

For me adding a contentView didn't really work as suggested. Moreover, it creates an overhead due to the added view (although I don't consider this a big problem). What worked best for me was just to turn off the ambiguity-checking for my scrollView. Everything is laying out nicely so I think it's okay in simple cases like mine. But keep in mind, that if other constraints for your scrollView break, the Interface-Builder will not warn you any more about it.

enter image description here

Nick Podratz
  • 622
  • 8
  • 17
  • 6
    This will just remove warning and do nothing to resolve the issue. – Predrag Manojlovic Jun 18 '17 at 22:09
  • 1
    You. are. my. hero. Did not realize this existed and am delighted to find it! I tried "Verify Position Only" which you would expect to, I don't know, verify the position only but no it allows this buggy "content size" issue as well. Gotta go with "Never Verify". Thanks! – Dustin Jan 03 '19 at 20:28
  • 1
    I think this is the right answer if you are creating the child view programmatically. Thanks! – Florian Kusche Mar 06 '20 at 15:03
6

Check out this really quick and to the point tutorial on how to get the scroll view working and fully scrollable with auto layout. Now, the only thing that is still leaving me puzzled is why the scroll view content size is always larger then necessary..

http://samwize.com/2014/03/14/how-to-use-uiscrollview-with-autolayout/

Mike Simz
  • 3,582
  • 4
  • 18
  • 34
4

Swift 4+ approach:

1) Set UIScrollView top, bottom, left and right margins to 0

2) Inside the UIScrollView add a UIView and set top, bottom, leading, trailing margins to 0 ( equal to UIScrollView margins ).

3) The most important part is to set width and height, where height constraint should have a low priority.

private func setupConstraints() {

    // Constraints for scrollView
    scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
    scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
    scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

    // Constraints for containerView
    containerView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
    containerView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
    containerView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
    containerView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
    containerView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true

    let heightConstraint = containerView.heightAnchor.constraint(equalTo: scrollView.heightAnchor)
    heightConstraint.priority = UILayoutPriority(rawValue: 250)
    heightConstraint.isActive = true
}
3

Using contentView (UView) as container inside UIScrollView, stick to edges (top, bottom, trailing, leading) of superview (UIScrollView) and contentView should have equalwidth and equalheight to superview. Those are constraints. And call of method:

-(void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    self.scrollView.contentSize = self.contentView.frame.size;
}

Solved issues for me.

Rishil Patel
  • 1,938
  • 3
  • 11
  • 28
3

See below: content view in scrollview vertical and horizontal centralized. you got ambiguity error, always make sure two added into scrollview from your content view is 1).button space to container.2)trailing space to constraint that is highlighted in screenshot,

these constraint means in scroll is how much you can scroll after your content view height or width.

enter image description here

it may help you.

Ravi Kumar
  • 1,249
  • 12
  • 21
3

I solved this kind of problem for my view by using "Resolve auto layout issues" > "Add missing constraints" for Selected View enter image description here

The following two constraints solve my problem:

trailing = Stack View.trailing - 10
bottom = Stack View.bottom + 76

in which: trailing, bottom are the trailing, bottom of UIScrollView

Linh Dao
  • 905
  • 1
  • 13
  • 25
3

In my case I received the issue of incorrect content size and content Size Ambiguity in iPad but was working in case of iPhone. I have done the following changes in storyboard to resolve the issue.

  1. Add scrollview in UIView and add constraints leading, top, trailing and bottom to 0,0,0,0.
  2. Set height of scroll view as per the requirements for eg. 100.
  3. Add UIView to scroll view and add constraints leading, top, trailing and bottom to 0,0,0,0 and align centre(X) and center(Y) constraints.
  4. Deselect “Content Layout Guides” in size inspector of scroll view.
2

@Matteo Gobbi's answer is perfect, but in my case, the scrollview can't scroll, i remove "align center Y" and add "height >=1", the scrollview will became scrollable

ygweric
  • 966
  • 1
  • 6
  • 22
2

People who are struggling with uiscrollview not scrolling just set your content view's bottom constraint with your last view's bottom layout (which is inside of your content view). Do not forget to remove center Y constraint.

Rest all the constraints are same as defined above. Scrollview only concerned about getting maximum height from its content view, and we are setting it as last view's bottom constraint, which means scrollview automatically will change its content offset.

In my case last view was UILable with no of lines property = 0(which automatically adjust its height depending upon its content) so it dynamically increase uilable's height and eventually our scrollable area increases because of uilable's bottom layout is aligned with our content view's bottom, which forces scrollview to increase it's content offset.

Siddhesh Mahadeshwar
  • 1,463
  • 13
  • 16
2

I made a video on youTube
Scroll StackViews using only Storyboard in Xcode

I think 2 kind of scenarios can appear here.

The view inside the scrollView -

  1. does not have any intrinsic content Size (e.g UIView)
  2. does have its own intrinsic content Size (e.g UIStackView)

For a vertically scrollable view in both cases you need to add these constraints:

  1. 4 constraints from top, left, bottom and right.

  2. Equal width to scrollview (to stop scrolling horizontally)

You don't need any other constraints for views which have his own intrinsic content height.

enter image description here


For views which do not have any intrinsic content height, you need to add a height constraint. The view will scroll only if the height constraint is more than the height of the scrollView.

enter image description here

Warif Akhand Rishi
  • 22,060
  • 6
  • 76
  • 101
2
import UIKit

class ViewController: UIViewController {

    //
    let scrollView: UIScrollView = {
        
        let sv = UIScrollView()
        sv.translatesAutoresizingMaskIntoConstraints = false
        return sv
    }()
    
    let lipsumLbl: UILabel = { // you can use here any of your subview
        
        let lbl = UILabel()
        lbl.translatesAutoresizingMaskIntoConstraints = false
        lbl.text = """
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce eleifend nisi sit amet mi aliquet, ut efficitur risus pellentesque. Phasellus nulla justo, scelerisque ut libero id, aliquet ullamcorper lectus. Integer id iaculis nibh. Duis feugiat mi vitae magna tincidunt, vitae consequat dui tempor. Donec blandit urna nec urna volutpat, sit amet sagittis massa fringilla. Pellentesque luctus erat nec dui luctus, sed maximus urna fermentum. Nullam purus nibh, cursus vel ex nec, pulvinar lobortis leo. Proin ac libero rhoncus, bibendum lorem sed, congue sapien. Donec commodo, est non mollis malesuada, nisi massa tempus ipsum, a varius quam lorem vitae nunc.
        
        Cras scelerisque nisi dolor, in gravida ex ornare a. Interdum et malesuada fames ac ante ipsum primis in faucibus. Maecenas vitae nisl id erat sollicitudin accumsan sit amet viverra sapien. Etiam scelerisque vulputate ante. Donec magna nibh, pharetra sed pretium ac, feugiat sit amet mi. Vestibulum in ipsum vitae dui vehicula pulvinar eget ut lectus. Fusce sagittis a elit ac elementum. Fusce iaculis nunc odio, at fermentum dolor varius et. Suspendisse consectetur congue massa non gravida. Sed id elit vitae nulla aliquam euismod. Pellentesque accumsan risus dolor, eu cursus nibh semper id.
        
        Vestibulum vel tortor tellus. Suspendisse potenti. Pellentesque id sapien eu augue placerat dictum. Fusce tempus ligula at diam lacinia congue in ut metus. Maecenas volutpat tellus in tellus maximus imperdiet. Integer dignissim condimentum lorem, id luctus nisi maximus at. Nulla pretium, est sit amet mollis eleifend, tellus nulla viverra dolor, ac feugiat massa risus a lectus. Pellentesque ut pulvinar urna, blandit gravida ipsum. Nullam volutpat arcu nec fringilla auctor. Integer egestas enim commodo, faucibus neque ac, rutrum magna. Vivamus tincidunt rutrum auctor. Cras at rutrum felis. Fusce elementum lorem ut pharetra venenatis.
        """
        lbl.textColor = .darkGray
        lbl.font = UIFont.systemFont(ofSize: 16)
        lbl.numberOfLines = 0
        return lbl
    }()
    
    //======================================================================//
    //
    // MARK:- viewDidLoad
    //
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupViews()
        setupAutoLayout()
    }
    
    func setupViews() {
        
        title = "ScrollView Demo"
        view.backgroundColor = .white
        view.addSubview(scrollView)
        scrollView.addSubview(lipsumLbl)
    }
    
    func setupAutoLayout() {
        
        scrollView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        scrollView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        
        lipsumLbl.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
        lipsumLbl.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        lipsumLbl.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        lipsumLbl.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
    }
}

Output:

enter image description here

Honey
  • 24,125
  • 14
  • 123
  • 212
iAj
  • 3,467
  • 1
  • 28
  • 33
1

Vertical Scrolling

  1. Add a UIScrollView with constraints 0,0,0,0 to superview.
  2. Add a UIView in ScrollView, with constraints 0,0,0,0 to superview.
  3. Add same width constraint for UIView to UIScrollView.
  4. Add Height to UIView.
  5. Add elements with constraints to the UIView.
  6. For the element closest to the bottom, make sure it has a constraint to the bottom of UIView.
Bitcon
  • 131
  • 1
  • 5
1

If you still have problems with UIScrollView, just turn off Content Layout Guides (Select your ScrollView in xcode Interface Builder -> choose Size inspector in right panel -> deselect 'Content Layout Guides') Or try these steps: xcode 11 scroll view layouts - it can be useful for new style of layout. Works fine at macOS 10.15.2, Xcode 11.3.1, for 05.02.2020

see screenshot

1

For any view, the frame and its content's sizes are the same ie if you have some content (e.g. image) with the size of 200 * 800 then its frame is also 200 * 800.

This is NOT true for scrollview's contents. The content is usually bigger than the frame size of the scrollView. If content is same in width, then you only scroll vertically. If it's same height then you only scroll horizontally. Hence it's the only view that needs 6 constraints not 4. For any other view having more than 4 required constraints will cause a conflict.


To setup your scroll view, its contents and position of scrolling, you basically need to answer three questions:

  1. How big is my frame? ie at any given moment how big should the scrollview be? e.g. I only want to use half of the screen's height so
scrollview.frame = (x: 0, y:0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height / 2)
  1. How much scrolling space do I need? ie How big is the content? e.g. the frame can be just 500 points of width, but then you can set an image with 7000 points, which would take quite some time to scroll horizontally. Or let it be exactly 500 points of width which then means no horizontal scrolling can happen.

  2. How much have you scrolled at the moment? Say your content's (or image) width was 7000 and the frame size is just 500. To get to the end of the image, you'd need to scroll 6500 points to the right. The 3rd part really doesn't affect the constraints. You can ignore that for now. Understanding it just helps how a scrollView works.

Solution

Basically if you leave out the 2 extra constraints (about the content size) then the layout engine will complain due to the ambiguity. It won't know what area of the content is hidden (not visible in the scrollView) and what area of the content is not (visible in scrollView) hidden.

So make sure you add size constraints for the content as well

But some times I don't add size constraints to my views and it just works. Why is that?

If all the contents you've added into the scrollview are constrained to the edges of the scrollview, then as the content grow the scrollview will add space to accommodate. It's just that you might be using UIViews where its intrinsicContentSize is 0 so the scrollView will still complain about ambiguity of its content. However if you've used a UILabel and it has a non-empty text, then its intrinsicContentSize is set (based on Font size and text length and line breaks, etc) so the scrollView won't complain about its ambiguity.

Honey
  • 24,125
  • 14
  • 123
  • 212
0

What I did is create a separate content view as shown here.

The content view is freeform and can has all subviews added to it with their own constraints in relation to the contentView.

The UIScrollView is added to the main view controller.

Programatically I add the contentView which is linked via IBOutlet to class and set the contentView of UIScrollView.

UIScrollView with ContentView via Interface Builder

Vlad
  • 4,915
  • 3
  • 32
  • 56
0

I was getting the same error.. i have done following

  1. View(Superview)
  2. ScrollView 0,0,600,600
  3. UIView inside ScrollView : 0,0,600,600
  4. UIView contains image view , label

Now add leading/trailing/top/bottom for scrollView(2) then UIView(3).

Select View(1) and View(3) set equally height and weight.. its solved my issue.

I have done the video that will help :

https://www.youtube.com/watch?v=s-CPN3xZS1A

Vinod Joshi
  • 7,094
  • 46
  • 49
0

[tested in XCode 7.2 and for iOS 9.2]

What suppressed the Storyboard errors and warnings for me was setting the intrinsic size of the scroll view and the content view (in my case, a stackview) to Placeholder. This setting is found in the Size inspector in Storyboard. And it says - Setting a design time intrinsic content size only affects a view while editing in Interface Builder. The view will not have this intrinsic content size at runtime.

So, I guess we aren't going wrong by setting this.

Note: In storyboard, I have pinned all the edges of scrollview to the superview and all the edges of stackview to the scrollview. In my code, I have set the translatesAutoresizingMaskIntoConstraints as false for both the scrollview and the stackview. And I have not mentioned a content size. When the stackview grows dynamically, the constraints set in storyboard ensure that the stack is scrollable.

The storyboard warning was driving me mad and I didn't want to centre things horizontally or vertically just to suppress the warning.

gtl_pm
  • 165
  • 1
  • 11
0

If anyone is getting a behavior where you notice the scroll bar on the right scrolls but the content doesn't move, this fact probably worth considering:

You can also use constraints between the scroll view’s content and objects outside the scroll view to provide a fixed position for the scroll view’s content, making that content appear to float over the scroll view.

That's from Apple's documentation. For example , if you accidentally pinned your top Label/Button/Img/View to the view outside the scroll area (Maybe a header or something just above the scrollView?) instead of the contentView, you'd freeze your whole contentView in place.

Dave G
  • 10,974
  • 7
  • 49
  • 74
0

As mentioned in previous answers, you should add a custom view inside the scroll view:

The custom view is the ContentView marked in the image

Add all your subviews to the content view. At some point you will see a scroll content view has ambiguous content size warning, you should select the content view and click the "Resolve auto layout issues" button (at the bottom right corner of the IB layout), and select the "Add missing constraints" option.

enter image description here

From now on when you run the project, the scroll view will automatically update it's content size, no additional code needed.

supergegs
  • 39
  • 4
0

You just have to make sure that there is a way to make a continuous line of constraints from the top to the bottom of the scrollview. [-X-X-X]

In my case - a horizontally scrolling scroll view - I also needed to add width and height constraints for each child of the scroll view, although Apple's technical note doesn't tell you this.

johnnyMac
  • 321
  • 2
  • 13
0

Set the ViewController's (the one holding the UIScrollView) size to Freeform in the size inspector in Interface Builder and all should work.

Freeform setting in Size inspector in Interface Builder for the containing UIViewcontroller

nico
  • 9,358
  • 8
  • 23
  • 28
0

Xcode 11+, Swift 5.

According to @WantToKnow answer, I solved my issue, I prepared video and code

Ahmed Abdallah
  • 2,081
  • 1
  • 16
  • 28
0

Using Autolayout

Add your scroll view inside a well defined view and then add the stack view inside the scroll view

Add top, left, right, bottom, center X and center Y constraints from scroll view and stack view to their relevant super views

Make sure that constraints are linked from stack view to the rightful superview (scrollview) since current default setting is to add an Align Top constraint and not a Top Space one.

Ahmed Elashker
  • 891
  • 1
  • 7
  • 16
-2

all the subviews inside a scrollview must have constraints touching all the edges of the scroll view, as its explained in the documentation, the height and width of a scroll view is calculated automatically by the measures in of the subviews, this means you need to have Trailing and leading constraints for width and Top and Bottom constraints for height.

-3

I think it is a 10 second work from now. I observed it in XCode 7.3 and made a video on it. Check here:

https://www.youtube.com/watch?v=yETZKqdaPiI

All you have to do, add a subview to UIScrollView with same width and height. Then select ViewController and press Reset to suggested constraint. Please check video for clear understanding.

Thanks

Vaibhav Saran
  • 12,548
  • 3
  • 61
  • 73