61
-ViewController
--View
---ScrollView (Top,Bottom,Leading,Trailing spaces to superview set to 0)
----ContentView (Top,Bottom,Leading,Trailing spaces to superview set to 0, Width equals with View (ViewController's child))
-----Label1
-----etc...

If i set a specific height constraint for my content view (e.g. 1000) the ScrollView works fine, but i got a static ContentView of 1000, which is not my goal, because my contentView got dynamic content, so it should be the height the content needs.

If i delete the height constraint for my ContentView, Xcode says:

Missing Constraints:
ScrollView need constraints for: Y position or height

ScrollView is actually pinned at top and bottom, so i don't know why Xcode want's a height constraint for the ScrollView...

What is the right way to go, when i want the ContentView height to be the height the content needs?

Bioaim
  • 928
  • 1
  • 13
  • 26

8 Answers8

181

Whenever using ScrollView with auto layout always follow below steps,

  1. ScrollView constraints: leadingSpace, topSpace, TrailingSpace, bottomSpace to superView and make sure when you control drag to add constraint, add it by pressing alt so that the constraint would be set without margin.

  2. Add UIView inside scroll view as container view and set its constraints: leadingSpace, topSpace, trailingSpace, bottomSpace to ScrollView without pressing alt button and set equalWidth to ScrollView.

  3. Whatever views you add inside this container view must have top to bottom constraint that is all view's should have vertical constraint, so containerView can calculate height required for itself based on the content inside it.

If the constraints are set correctly then the scrollView will set its content size automatically based on the component inside it and you do not need to set the content size manually, also the scrollView will only scroll if the component inside the container view is not fitting inside otherwise it won't scroll. If you want to make it scroll anyways then you need to check the Bounces Vertically property from storyboard to get the bounce effect.

Note: While you set constraint to the component inside the scrollView, you will see the constraint warning till you set the constraint from top component to the bottom one, aways remember that your top component should have top constraint (Vertical constraint) to superView and the component at the bottom should have bottom space constraint to the super view. When this satisfy then all warning will disappear eventually.

ScrollView constraints:

enter image description here

ContainerView constraints:

enter image description here

Bharat Modi
  • 4,158
  • 2
  • 16
  • 27
  • You added "leadingSpace to scrollView" three times. – Nicolas Miari Feb 25 '16 at 11:55
  • my last control will be a MapView, which i generate at runtime, does this work this way aswell? – Bioaim Feb 25 '16 at 12:06
  • Yes, it will definitely work. What i can suggest you is, don't create and add mapView programatically, add it from IB and set its height constraint to 0 as you want to show it at run time. Make outlet of mapViews height constraint and when you want to show your mapView just do this mapViewHeightConstraint.constant = ; [self.view layoutIfNeeded]; and it you want to hide your mapView again set it to 0. If you want to increase mapView height animatically just put layout as this [UIView animateWithDuration:0.3 animations:^{ [self.view layoutIfNeeded]; }]; – Bharat Modi Feb 25 '16 at 13:29
  • 5
    This answer is excellent!! I finally understood how to set up the constraints correctly in a ScrollView, thank you very much – Nahuel Roldan Aug 18 '16 at 13:50
  • Seems that equal height from container to scrollview is needed aswell – thibaut noah Dec 14 '16 at 11:06
  • No you should not set height as the scrollView and the containerView will calculate the height required for itself. – Bharat Modi Dec 14 '16 at 11:19
  • Following point 1 & 2 (no element is added in contentview), I am still receiving an error for scroll view height or Y position : Xcode 8.2 – Jamal Zafar Jan 14 '17 at 17:27
  • @JamalZafar You would need to add at least one element in the container view (with fixed height if the element type does not have intrinsic constraints). – Bharat Modi Jan 16 '17 at 06:21
  • 3
    Been searching for literally 2 years for an answer like this, explaining how the mechanics of setting up a ScrollView works. Salutations. – instanceof Feb 07 '17 at 09:10
  • @BharatModi I am facing the same problem as Jamal Zafar. Even after adding an element in the contentView, the scrollView shows the "Missing Constraint" error. – K.K Jun 19 '17 at 08:06
  • @K.K Warning wont go until and unless content View gets/can able to calculate height required for components inside. You can the try one trick, set fixed height to each component (if there are many), and see when the warning go away and then try removing that fixed height constraint from component. (This is because some of the component like button textView, uiview required height constraints.). – Bharat Modi Jun 23 '17 at 04:41
  • @BharatModi How does your answer get affected when 3. 's "Whatever Views" is a StackView (Vertical)? – Greg Hilston Aug 16 '17 at 17:36
  • I have not tried this with UIStackView's. However this should work for StackView's too. – Bharat Modi Aug 21 '17 at 09:26
  • Works and explained very well! – Lance Samaria Nov 10 '17 at 19:53
  • Working perfectly, even in very nested and weirdly designed views! The containerView matching Equal Widths to scrollview (i.e. the uiview's superview) was a life saver! I couldn't get the ui views inside to align to the right for some reason. Thanks for that! – CyberMew Jul 12 '18 at 08:59
  • It's probably worth noting for point 3 that an explicit hight must be able to be calculated. I had a constraint where the vertical distance had to be greaterThan or equal to a constant. That caused me to get the error "Need constraint for: Y position or height". Making the constraint equal to not greaterThan or equal to solved this. – TMin Oct 30 '19 at 00:21
  • I am doing all of the things and I still get "Scroll view needs constraints for Y position or height"". The content view has constraint for width equal to the safe area. If I give that content view a static height it works but I do not want to do that :( – Vladimir Amiorkov Apr 30 '20 at 09:00
13

Xcode 11

I've been following several tutorials on this for a few hours now, and none of them seem to work. It seems that Xcode 11 has some updates that change how the scroll views work with auto layout.

  1. Add a UIScrollView to the view and add top, bottom, leading, and trailing constraints.
  2. Add a UIView to the scroll view. We will call this the content view.
  3. Add top, bottom, leading, and trailing constraints from the content view to the scroll view's Content Layout Guide. Set the constraints to 0.
  4. Add an equal width constraint between the content view and the scroll view's Frame Layout Guide. (Not the scroll view or the main view!)
  5. Temporarily add a height constraint to the content view so that you can add your content. Make sure that all content has top, bottom, leading, and trailing constraints.
  6. Delete the height constraint on the content view.

    I found an excellent tutorial at this link.

swiftyboi
  • 2,965
  • 4
  • 25
  • 52
3
  1. Select your view controller
  2. Uncheck 'Adjust Scroll View Insets'

enter image description here

ali ozkara
  • 5,425
  • 2
  • 27
  • 24
2

Make sure the bottommost element inside of your content view inside of your scroll view has bottom space constraint set to 0 and make sure all elements inside content view have height set.

This makes content view resize according to elements inside it and you don't have fixed height of your scroll view/content view and your scroll view will resize with phone's screen size.

Babken Vardanyan
  • 14,090
  • 13
  • 68
  • 87
2

If you have UIScrollView with UITextView inside complaining that:

"ScrollView needs constraint for y position or height". Or "UIScrollView Scrollable Content Size Ambiguity"

Just uncheck default “Scrolling Enabled” on UITextView in the IB. Works like magic :) enter image description here

craft
  • 2,017
  • 1
  • 21
  • 30
Vitya Shurapov
  • 2,200
  • 2
  • 27
  • 32
1

It will work

-ViewController
--View
---ScrollView (Top,Bottom,Leading,Trailing spaces to superview set to 0)
----ContentView (Top,Leading,Trailing spaces to ScorllView set to 0 | Height to dynamic (1000))
-----Label1
-----etc...

Do same for your ContentView , Your Own Calculation for your Content

- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:YES];
[self adjustHeightOfTableview];
}

- (void)adjustHeightOfTableview
{
CGFloat height = tblMainMenu.contentSize.height;
CGFloat maxHeight = tblMainMenu.superview.frame.size.height - tblMainMenu.frame.origin.y;

// if the height of the content is greater than the maxHeight of
// total space on the screen, limit the height to the size of the
// superview.

if (height > maxHeight)
    height = maxHeight;

// now set the height constraint accordingly
self.tableViewHeightConstraint.constant = height;
[UIView animateWithDuration:0.1 animations:^{
    [self.view setNeedsUpdateConstraints];
}];
}

Edit 1

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    NSString *OptName_length = @" Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam";
    NSDictionary *attributes = @{NSFontAttributeName: [UIFont systemFontOfSize:17.0]};
    CGRect rect = [OptName_length boundingRectWithSize:CGSizeMake(tableView.bounds.size.width-150.0, MAXFLOAT)
                                                  options:NSStringDrawingUsesLineFragmentOrigin
                                               attributes:attributes
                                                  context:nil];

    CGSize requiredSize = rect.size;
    return requiredSize.height +5.0f;
    }

Edit 2

Check the site, this will help you... uitableviewcell-dynamic-height-with-autolayout-conclusion

Mohamed Jaleel Nazir
  • 5,776
  • 3
  • 34
  • 48
1

Bharat Modi's answer pretty much solves the issue, but I (Xcode 8.3.2, iOS 10 SDK) also had to match the Content View's height and width to UIScrollView's height and width.

This will pin the content size to just visible area, but it makes IB happy. Then (I think) it's just a matter of calculating the content size correctly and setting it programmatically. Which I would've had to do anyway, since if you have dynamic content you can only do that at run time.

You might also need to tweak the "Adjust scroll view insets" settings of the view controller if you have a navigation bar.

This is what I have:

UIScrollView in IB without warnings

Note that this could be just a peculiarity of my setup, because the official suggestions (https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithScrollViews.html) also don't mention that this needs to be done.

I tried figuring this out using just a scroll view, a content view and another dummy view of fixed width and height to imitate the content, but nothing seemed to make IB happy.

(Sorry, I don't have enough rep to put this as a comment on the original answer).


UPDATE:

So actually what I ended up doing is setting my Content View to a fixed height in IB and creating an outlet for that height constraint in the code. Then after the view has loaded all of its dynamic content I just update the height constraint like so:

self.uiContentViewHeightConstraint.constant = mapViewBottomY + 15

And everything works. The key here is basically that when there's a view inside a scroll view - that view defines scroll view's content size. As people have mentioned before, size of content view has to be fully defined at build time in order for IB to be happy. You are free to manipulate the values at run time though through outlets - it's easy and safe.

One advantage of having the content view at fixed size in IB is that since you've fixed the content size, views inside the content view can now be defined as usual, using relative offsets.

denis.kim
  • 61
  • 5
-1

Set your label left top right and bottom margin constraint with content view of scrollview, and set number of line of UILable to 0. It will expand your content view as per the size of your content

enter image description here