Using UIScrollView with Auto Layout in iOS

Who says you can’t teach an old control some new tricks?  The UIScrollView has been around since the beginning of iOS, and there have been many blog posts, Stack Overflow questions, and Apple documentation covering how to set up your content to scroll inside a UIScrollView with the old springs & struts layout system.  

Since the introduction of Auto Layout to iOS, there is a new way you can configure your scrolling content. With Auto Layout, the amount of code you have to write is greatly reduced.

One of the big pain points with the old way of setting up a UIScrollView was communicating the content size to the scroll view. It was fairly straightforward to calculate your content size if the content in the UIScrollView was an image. But it was not as easy if your scroll view included a mixed bag of buttons, labels, custom views, and text fields. Lengthy code adjustments were needed to reflect constant changes in device rotations and phone size differences.  

In this blog post, I’ll show you how to set up a UIScrollView with Auto Layout that is responsive to portrait and landscape changes. I will also show you how the scroll view can move your content out of the way of the pop-up keyboard.

Create a Basic Layout in Interface Builder

I want to give you a sense of what we are building so you can follow along and see how the view is constructed. I created a view with some labels, text fields, and an image. If you want to follow along, I put the entire project on GitHub. Here is what it should look like in portrait and landscape.

(For demo purposes, I colored the scroll view with a yellow background and the content inside with a blue background. When in portrait mode, the content will not scroll. In landscape mode, the content can scroll vertically especially when the keyboard covers up most of the view.)

uiscrollview-complete-landscape2
uiscrollview-complete-portrait2

Adding a UIscrollView with constraints

Now let’s get started building the UI. In interface builder, drag a UIScrollView and add it as a sub view of the view controller’s main view. Now add some constraints to your scroll view to place it where you want it in your main view. In my example, the scroll view takes up the whole view, so I added four constraints from the scroll view’s edges to the main view with zero spacing. Your view hierarchy should look like the image to the right.

The following are the four constraints that I added to get the scroll view constrained to the super view.  Your constraints may look different if you do not want the scroll view to occupy the entire screen.

adding-a-uiscrollview-with-constraints3

Use a Single Child View to Hold All of Your Content

The next step in laying out our controls is to create a single child view of the UIScrollView where we will put all of our content. Using a single child view will simplify the constraints we have to add later. If your content is only a scrolling image in a UIImageView, this can serve as the single child view. In the example below, I gave the child view a name of Content View.

Contain content of UIscrollView in one UIView

Our next step is to add constraints from the content view to the scroll view. The change they made to UIScrollView, to support Auto Layout, is that it can automatically calculate the content size if you set up your constraints the right way. You need two sets of constraints.

Width or Height Constraint

Usually you only want your content to scroll in one direction. In my case I want the scroll view to scroll vertically. Therefore I need to set the width of my single content view to be the width of the scroll view. Use this equal width constraint to set the width of your content (if you are scrolling vertically) or equal height to set the height (if scrolling horizontally).

Edge Constraints

Attach four constraints (top, bottom, left, right) from our single content view to the scroll view. This might seem redundant considering we just added an equal width constraint in the previous step. However this part is the most confusing because Apple has repurposed the constraints in this case to indicate to the UIScrollView the boundaries of your content and therefore calculate the content size. These special constraints, from your content view to the UIScrollView, do not behave like normal constraints. No matter what constant value you give them, they will not resize your content view.  Once they are in place, the UIScrollView can calculate its content size. The only place I could find documentation on this new behavior is in a tech note TN2154 article by Apple. The only mention is in the section titled “Pure Auto Layout Approach”

UIScrollView with constraints on content to determine content size

Go ahead and add the top, bottom, leading, trailing, and equal width constraints from the content view to the scroll view. When finished, you will notice we are getting some Auto Layout errors. Without any controls inside the content view, or if there are no placeholder width and height constraints on the content view, the scroll view cannot determine the content size.

contentsize-is-derived-from-contentview3

Ignore the errors for now. The next step is to add whatever content you want to scroll inside the content view and use Auto Layout to constrain the items inside the content view. Make sure you have constraints attached to all four sides of the content view so that it will expand to the size of your content. If you need to, you can increase the simulated size of your view controller in interface builder to give you room to layout all of your scrolling content. To do this click on the view controller, select the size inspector and select Freeform size.

Add content to the container view

Go ahead and run the project. Your content should scroll and look good in portrait and landscape rotations.

completed landscape view
Completed portrait view

Moving Content under the Keyboard into View

If you have UITextFields near the bottom of your content view and the keyboard pops up, it blocks the bottom half of your screen; you cannot see what you are typing. The scroll view allows us to scroll the content into view.

Keyboard covers the bottom of your screen

We first need to keep track of which text field is currently being edited. You can do this many different ways, but I chose to add the view controller as a delegate to the UITextFields. In interface builder Ctrl – Drag from each UITextField to the view controller and set it as the delegate.

Add View Controller as delegate for UITextFields

Now we can implement a couple of delegate functions to keep track of which field is active. We do this to make sure that the active field is visible when the keyboard pops up.


weak var activeField: UITextField?

func textFieldDidEndEditing(_ textField: UITextField) {
    activeField = nil
}

func textFieldDidBeginEditing(_ textField: UITextField) {
    activeField = textField
}

Now we need to register for keyboard notifications. In the viewDidLoad function, add the view controller as an observer. You can unregister from these notifications in the deinit function.


override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(SCRViewController.keyboardDidShow),
        name: UIResponder.keyboardDidShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(SCRViewController.keyboardWillBeHidden),
        name: UIResponder.keyboardWillHideNotification, object: nil)
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

Finally, add an outlet to your scroll view and implement the keyboard notification selectors. If this code looks familiar, it is based on the solution from Apple’s documentation. I add the height of the keyboard to the scroll view’s content inset so that the scroll view has enough padding at the bottom to scroll the very bottom text field up above the keyboard. As the final step, I check to see if the active text field is visible and scroll the field into view if it is not.


@objc func keyboardDidShow(notification: Notification) {
    let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
    guard let activeField = activeField, let keyboardHeight = keyboardSize?.height else { return }

    let contentInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardHeight, right: 0.0)
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets
    let activeRect = activeField.convert(activeField.bounds, to: scrollView)
    scrollView.scrollRectToVisible(activeRect, animated: true)
}

@objc func keyboardWillBeHidden(notification: Notification) {
    let contentInsets = UIEdgeInsets.zero
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets
}

This is what it looks like when it’s all working. Once you start editing a text field, the keyboard animates into view, and your scroll view animates the active text field to be above the keyboard. If you would like to try this code out yourself to see it in action, I have the entire project on GitHub.

uiscrollview-with-autolayout
 

Conversation
  • massimo says:

    Very good and clear post: thanks for sharing!
    I lost two days trying to understand what the Apple documentation intended (as always, the Apple docs are clear if you know the subject!): this solved everything.

    • Mike Woelmer Mike Woelmer says:

      Glad you liked it Massimo.

      • Aman says:

        Hi Mike ,
        How can i Set constrain when my scrollview contain view which has greater height than scrollview ?

        Thanks
        Aman

        • Lora says:

          Hello, Aman,
          Your question is old, but I am answering in case another person needs to find the answer.
          Make your view controller’s main view freeform and then resize it to visually accommodate all of your content. It doesn’t affect the view at runtime, it just resizes it in interface builder, in order for you to see and align all of your content.

  • Jack Bond says:

    I’ve done HTML hacking, Android, Windows Forms, WPF, Silverlight, and probably more. I am now in the process of learning iOS, and I can say with authority, that the iOS layout system is just about the most pathetic vomit I have ever seen inflicted on the development community. I stumbled upon this page when trying to figure out what was going on with the UiScrollView, and wanted to say thanks. That said, if anyone believes that iOS will ever be seriously be adopted by corporate developers, they are INSANE. XCODE is a joke. The SDK is a joke. Objective-C is a joke. It’s no wonder iPhone market share is down to 16%. When iPhone is as irrelevant as Blackberry in five years, it should come as a surprise to no one. What a horrible horrible platform.

    • Mike Crandall says:

      Jack, you are wrong. Sorry. Sounds like you are merely having a problem learning it.
      Peace.

    • Andrew says:

      I kind of feel the same way.
      From all platforms, the iOS layout system is unnecessarily complicated.
      It’s like ten thousands spoons when all you need is a knife.

  • Jack Bond says:

    There seems to be a bug in the keyboardDidShow method. I’ve copied your method verbatim, and it does put the focus on the selected textbox, but my form fields take up the entire screen in portrait. Problem is, after scrolling to the bottom, when I try to scroll to the top of the form, it won’t let me get all the way to the top. It’s seems like the scrollview hasn’t properly calculated the form height plus the keyboard height. I must say, it’s rather pathetic that iPhone developers have to handle this type of nonsense. What a horrible horrible platform.

    • Mike Woelmer Mike Woelmer says:

      Jack,

      Have you tried using a visual inspection tool like http://www.sparkinspector.com to see what your visual tree looks like? The KeyboardDidShow only adds a content inset to the scrollview (doesn’t take away space), so you should still be able to scroll to the top. My guess is you have some other layout issue.

  • Chris Palmer says:

    Was the intent also to scroll the controls if there were a lot of controls on the form? I went through this example and I could swear at some point my “big” form with lots of controls would allow me to scroll down to the other controls. Then it stopped working. Although the keyboard substance of the post does work. However I would assume if you had controls out of view it would allow the user to scroll to them. Perhaps I did something wrong.

    • Mike Woelmer Mike Woelmer says:

      Chris,

      In my sample, the content will scroll if there is not enough space to show all of the content. For instance if you rotate the phone to landscape or in portrait mode if you have a 3.5 inch display.

      In your code, check the following things. Do you have one child content view of the scroll view? Are there leading, trailing, top, and bottom constraints binding the content view to the scroll view (this will tell the scroll view your content size)? Is your content view the correct size at runtime? Perhaps you have an explicit width or height that is not marked as placeholder. You can either NSLog some sizes at runtime or use a tool, like spark inspector, to visually see how the parts of your UI are rendered.

  • Peter Smith says:

    Great post. I have precious little hair left, so tearing out further hair wondering why my content only stretched halfway across the scroll view horizontally was not proving constructive.

  • Brian Ziegler says:

    I found this really helpful. I am using a navigationBar with my project. It was easy to allow for it in the code.

    CGFloat navBarAllowance = self.navigationController.navigationBar.frame.origin.y + self.navigationController.navigationBar.frame.size.height;
    UIEdgeInsets contentInsets = UIEdgeInsetsMake(navBarAllowance, 0.0, kbRect.size.height, 0.0);
    self.scrollView.contentInset = contentInsets;
    self.scrollView.scrollIndicatorInsets = contentInsets

  • Robert says:

    Hi. Thank you for this article. Where in the Apple docs did you find this info about the UIScrollView? Specifically, the point #2 about how the constraints between the UIScrollView and it’s subview(s) are ignored, or not treated like normal constraints but instead used to calculate the “content size”. I don’t see this in the Apple docs.

    • Mike Woelmer Mike Woelmer says:

      Hi Robert,

      Here is a link to a tech note TN2154 article by Apple. Look at the section titled Pure Auto Layout Approach and read the third bullet. It was not easy to find, which is why I thought the subject would make for a good blog post. Enjoy.

  • Robert says:

    Thanks. I had actually seen that note, but without your post it wasn’t clear. Now it makes sense.

  • Gabriel Afonso says:

    Great post!

  • Erik says:

    Wow, I don’t usually comment on random blogs, but this was the best explanation of AutoLayout and UIScrollViews I have found! Thank you very much. I think your solution with the contentView in the scrollView is the least hacky method I’ve come across.

  • Katie says:

    I have a uiview pinned to the main view, inside of this I have a scroll view. The scrollview is pinned to its parent view. Sub views within the scrollview will resize if you have them pinned to the scrollview and also add in a horizontal central alignment constraint on the subview of the scrollview. The ey will then stretch on auto rotation and no additional constraints in code are needed. No idea why this works but it does!!

  • Vinuraj M V says:

    Thanks for the post. Helped me in a crucial time :)

  • Martin says:

    Hello Mike,
    Thanks for the wonderful tutorial. It was very useful. However, since I was using a navigation bar, the inset started cutting a part of my scrollview, which didn’t get back to normal once the keyboard disappeared. Maybe I’ve done something wrong, but I was able to fix it this way:
    – (void) keyboardDidShow:(NSNotification *)notification
    {
    NSDictionary* info = [notification userInfo];
    CGRect kbRect = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    kbRect = [self.view convertRect:kbRect fromView:nil];

    self.scrollViewBottomConstraint.constant = kbRect.size.height;
    }

    – (void) keyboardWillBeHidden:(NSNotification *)notification
    {
    self.scrollViewBottomConstraint.constant = 0;
    }

  • Randy Weinstein says:

    Will setting up adaptive layout with XCode-6 eliminate the need for code implementation of context-specific constraints? I just built a form with 8 text fields that layout vertically in iPhone portrait or landscape ( w:compact h:any in adaptive layout speak ) and in two columns for ipad portrait or landscape ( w:regular h:any in adaptive layout speak ). Height and width of each text field are constant and these size constraints apply in any display context ( h:any w:any in adaptive layout speak). That worked in a standalone view except that the bottom 4 text fields are not visible in iphone landscape. I’m thinking that inserting the form into a UIScrollView will solve the problem and auto layout augmented with adaptive layout will manage all the layout use cases without having to do any coding.

  • Kevin says:

    I’ve following this tutorial and I get the following message: I have no clue how to fix this. Any advice?

    2014-08-15 14:46:06.093 ScrollViewTest2[3020:60b] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don’t want. Try this: (1) look at each constraint and try to figure out which you don’t expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you’re seeing NSAutoresizingMaskLayoutConstraints that you don’t understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
    (
    “”,
    “”,
    “”
    )

    Will attempt to recover by breaking constraint

    Break on objc_exception_throw to catch this in the debugger.
    The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in may also be helpful.

  • Nice post. I was not able to get things to work right before, but this really helped. Please note that your code breaks in XCode 6 beta 5 (SIGABRT, because you cannot establish a constraint between leading and left, or trailing and right). The solution is simply to replace NSLayoutAttributeLeft (resp. NSLayoutAttributeRight) with NSLayoutAttributeLeading (resp. NSLayoutAttributeTrailing). I am also left to wonder whether the trick is still necessary in this newer version of XCode. Please share if you have any insight. Cheers!

    • David says:

      Thank you so much, i had exactly the same Problem with Xcode 6 beta 6 and your solution solved it!!! I´m also interested, if this is now the correct solution or a xcode 6 bug? Any new suggestions?

      • The message that is delivered in the console when you crash seems to indicate that it is Apple’s intent, i.e. do not mix elements of a different nature in a constraint. And thanks for the reminder to go get beta 6 ;-).

        • amau96 says:

          he attributes leading and trailing are the same as left and right for left-to-right languages such as English, but in a right-to-left environment such as Hebrew or Arabic, leading and trailing are the same as right and left. When you create constraints, leading and trailing are the default values. You should usually use leading and trailing to make sure your interface is laid out appropriately in all languages, unless you’re making constraints that should remain the same regardless of language (such as the order of master and detail panes in a split view).

          http://stackoverflow.com/questions/19971508/difference-between-nslayoutattributeleft-vs-nslayoutattributeleading

      • Also, I just tried in beta 6 and XCode barfs in the console, suggesting that it is unable to satisfy simultaneous constraints between mainview-scrollview, scrollview-contentview, and mainview-contentview, and breaking one of the conflicting constraints to solve the problem (namely, the leading constraint between scrollview and contentview). Thus, it seems that this constraint can simply be removed, and it seems to work well so far, but I wish Apple would clarify and clean this up once for all. Maybe for the final release of XCode 6…

  • Ronald says:

    This is SO helpful, thank you very much. Was scratching my head for at least a few hours before I found these.

  • ethan says:

    Nice post, but the key: UIKeyboardFrameBeginUserInfoKey should be UIKeyboardFrameEndUserInfoKey in my project, maybe we are not using same language, I am in Chinese.

  • Sara says:

    I am left with one question:

    Why can’t I make the constraint between contentView and the container of scrollView from interface builder?

    I guess it was a corner case that broke compilation so they just made it impossible for now?

  • Josep says:

    Hi, could you upload the xcode project for this demo? It might help for better understanding.

  • Jeremy says:

    Great post. thanks man!

  • Anil says:

    Nice and helpful Post .Thanks man ….

  • Winsey says:

    Thanks for the good tutorial. But I found that when the textfield is connected to an IBOutlet in the controller, the it will no longer be appear above the keyboard (it will scroll to that field actually, but just showing the top edge of the textfield).. :(

  • Gustavo says:

    Man, you are a life savior!
    Thanks very much for this tutorial! The coding part just solved the whole thing.

  • Hashem says:

    Thanks for your article. that was very nice. but I think there is a bug in Xcode 6 when I add subview to the scrollView in the interface builder, the subview will not be subview of scrollview until viewDidAppear get called

  • Diego says:

    Nice tutorial about UIScrollview and Autolayout. Unfortunately, it’s not the correct solution to the example problem. You can use a UITableViewController with a static tableView to layout your form. The form will automatically scroll when on landscape and when the keyboard appears it will focus on the parent UITableViewCell. This can be done since iOS5.

  • Kelvin says:

    A great post. But when I add the code in the viewDidLoad: method, I got crash.Info like:”The view hierarchy is not prepared for the constraint.Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view? That’s illegal.”
    I am sure the contentView is right subview of the ScrollView, and the outlet without any problem. Did anybody else get the same problem?

    • Kelvin says:

      I found it when I uncheck the Sizeclass, everything goes well.

    • Lei says:

      Hi Kevin, have you found a solution? I’m encountering this too.

      Thanks,
      Lei

    • Greg Michaelson says:

      Add the constraint to viewDidAppear instead of viewDidLoad…

  • dnacingbush says:

    Where do we find width constraints setting in Xcode 6.1.1?
    Any chance there be a tut in Swift?
    Cheers

  • AwwYisss says:

    OMG THANKS MAN YOU’RE ABSOLUTELY AWESOME!!!

  • Sam Clewlow says:

    The solution to the width problem is to set the content views width equal to the scroll views width, as you will be matching the scrollviews *frame* width, which in turn is being defined by the view controllers width. This can be done in IB.

    • Uwe says:

      indeed – thats it. Thanks Sam for pointing this out.

  • Lei says:

    Hi Mike,

    Thanks for the post. Though I’m encountering this error when I added the width and height constraint programmatically for the content view in viewDidLoad :

    “Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view? That’s illegal. ”

    Have I done something wrong?

    Thanks,
    Lei

  • Neil says:

    You are a gentleman and a scholar.

  • Kevin says:

    I too am encountering the issue with “The view hierarchy is not prepared for the constraint”.

    Any solutions?

    • Greg Michaelson says:

      Add the code constraints to vidDidAppear instead of viewDidLoad… That fixed for me.

  • Jay says:

    I like your post. But unfortunately, some parts of your instructions are rather ambiguous. Trying to convert the codes into Swift is a nightmare for a learner.

  • Pat G says:

    @Jay I am not sure whether you have already figured out how to implement the scrollview using autolayout in swift. Here is one way to implement it .

  • Gopala says:

    UITextfield not select (user interaction) why it is behave i did not understand

  • Juan says:

    UIScrollViewWithAutoLayout You’ve implemented swift

  • j.f. says:

    iOS 9 complains about the left and right constraints you create. It doesn’t like that you mix NSLayoutAttributeLeading with NSLayoutAttributeLeft and NSLayoutAttributeTrailing with NSLayoutAttributeRight. It wants them to be the same.

    Simply using one or the other instead of mixing and matching satisfies the complaint. iOS 8 apparently doesn’t care if they are mixed but is still obviously happy if they are the same.

  • Greg Michaelson says:

    You have to add the layout constraints to viewDidAppear… not viewDidLoad…

    That solves the “hierarchy is not prepared for the constraint” problem.

  • Callebe says:

    Very good tutorial.

    It have helped me a lot.

    Instead add the constraint to the containerView related to the super view writing code, I have added a Equal Widths constrant related to the scrollView, and it worked for me. That way, the container view will have the same width of the scrollView.

    Thank you very much.

  • steven says:

    Thanks for the tutorial , I’m a new commer to ios development and this platform is sooooo complicated that i’m about to give up. I’m a android and windows phone 8 developper and I do not understand why this control is so complicated in ios. I spent 15min in android and windows phone to integrate the component. But I’m struggling to integrate it in ios since 5 days. I think apple should adopt the same simplicity of android and windows phone platforms.This tutorial finally help me to get the job done.thanks

    • Geoff says:

      You and me both buddy……..lmao

      Well, we know Apple is furiously exclusive about everything it makes and does… I’m sure iOS could have been designed to accommodate C++ devs or something, but we should expect Apple to be “different” with their choice of programming language as well.

      It’s a pretty nightmare-ish beginning when you’re used to methods->thatAll(look,like,this). I can’t say I’ll ever love OC, but I think it’s worthwhile trying to get along with it as best we can. It gives you access to an awfully large market share in the consumer handheld market after all :)

  • Geoff says:

    It seems that learning how to master ScrollView is a rite of passage for iOS development. I’ve never seen so many experienced developers pulling their hair out over the fundamentals like this!

    Anyway, this tutorial gets to the point, and provides a near-universal solution, as opposed to a hacky anecdotal one. Great work!

  • Marius le Roux says:

    Wel, well … maybe apple should go and have a look at how Android handles the scrollview issue as well as the keyboard over your input fields issue. Never in my life have I struggled like this to get a scrollview type control to actually … well, scroll!!!

    Maybe even have a look at a modern IDE, like DELPHI 6 ;-), for instance where you could solve crap like this with ANCHERS!

    Do apple developers actually LIKE to struggle?

  • Ben Manning says:

    I found that adding an Equal Width constraint between the scroll view and the content view meant that I did not need to add constraints in code!

  • Jamie says:

    The tip about “your content view can’t depend on the scroll view for its size” really saved me. I was yelling at my computer until I found this article. Thanks!!

  • Ryan says:

    I’d love to see a follow up on this if you have any more suggestions on IB + Scrollview + keyboard.

    One thing I know that can be improved is setting a equal width relationship between your content view and the parent ViewController. You can do that in IB by control clicking from the side panel.

    I was hoping there is a way to change the content size from IB also so I don’t need the keyboard notifications. But I’ll do it that way for now. Thanks!

    • Mike Woelmer Mike Woelmer says:

      Thanks Ryan, I just updated the post and the code to work in Xcode 7. Plus I added Swift.

  • I tried reading Apple’s Technical Note on UIScrollView and AutoLayout but this guide made much more sense.

    Thanks for taking the time to write it, and thanks again for sharing it. The content has been a real time saver.

  • Alfred says:

    Can you add a UITextView in to the form. Forms with UITextFields are working. But when I add a UITextView, I face issues

    • Mike Woelmer Mike Woelmer says:

      Hi Alfred,

      UITextFields have an intrinsic content height but not width. Therefore you can stack them one on top of the other and your content view, that contains them, will have an intrinsic content height that is the sum of all of the stacked fields. UITextViews however do not have an intrinsic content width or height. Therefore you need to set an explicit height or make their height relative to other controls. In my example, if I added a UITextView, I would pin the leading and trailing edges to the content view (content view gets it’s width from the main view controller’s view, so I don’t need to set an explicit width on the UITextView). Then I would either give the UITextView and explicit height of say 300 or make the height of the UITextView relative to some other control that has an explicit height. For instance I could say I want my text view to be four times taller than my labels or the same height as my profile picture. The later is better than setting an explicit height because it would look better on the different size phones. Hope that helps.

  • Raphael says:

    Thank you so much for the post! I have a problem though that I’m not able to solve. How would you do if you want the “terms and policy” anchored to the bottom of the screen? In that scenario you actually don’t have constraints traversing from the top to the bottom of the content view because you wouldn’t add a constraint (fixed vertical space) between the terms and policy and the previous element (Password confirmation).

    • Mike Woelmer Mike Woelmer says:

      In that case I would not have the scrollview occupy the entire screen. I would have the scrollview and the terms & conditions be siblings with the scrollview on top of the terms and conditions. That way the T & C would always stay at the bottom.

      –Mike.

      • Raphael says:

        Wow, indeed that makes sense, thank you! Also, one more thing you may like to add on the tutorial. If you just open your project and put your view controller as rootViewController of a UINavigationController it won’t look right due to property automaticallyAdjustScrollViewInset which defaults to true. If you set it to false (or uncheck on the storyboard) it will look right. I was struggling with this and realised your example is not inside a navigation controller.

      • Raphael says:

        If you want I can make a pull request.

  • KUmar says:

    Thanks for sharing …

  • Robert Menke says:

    You are a godsend my friend. I searched for 3 days through different tutorials to find an answer to this including posting 2 questions to stackoverflow and read this tutorial through 1 time and finally understood how to accomplish this. I think I just woke up the neighbors with a loud cheer of joy!

  • Daniel B. says:

    Thank you for the walkthrough Mike. It’s hard to find documentation on AutoLayout+UIScrollView. Struggled with this for several hours, and still it feels like it works when it wants to.

  • Sivaganesh says:

    Hi Mike ,
    It is a very good ,tutorials to understanding the orientation layout issue in scroll view ,thanks a lot man

  • David Rhodes says:

    I made a slight improvement that considers the case where the textview (or textfield if that is what you are using) is not in self’s view (e.g. in a sub container). In this case, you need to translate the textView (activeTextView in my code below) location to self before deciding if scrolling is needed. I also check to see if the whole textview is in the visible area, rather than just its point origin


    func keyboardDidShow(notification:NSNotification) {
    if activeTextView != nil {
    let userInfo = notification.userInfo!
    let ht = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().height
    let contentInset = UIEdgeInsetsMake(0.0, 0.0, ht, 0.0)
    totalScrollView.contentInset = contentInset
    totalScrollView.scrollIndicatorInsets = contentInset
    var aRect = self.view.frame
    aRect.size.height -= ht
    // convert the textView's bounds to self's frame:
    let tvBounds = activeTextView!.bounds
    let tvTranslated = self.view.convertRect(tvBounds, fromView: activeTextView!)
    // if the translated frame is not fully in visible area, scroll
    if !aRect.contains(tvTranslated) {
    totalScrollView.scrollRectToVisible(tvTranslated, animated: true)
    }
    }
    }

    • Glen Ruhl says:

      Wow. This just helped me make a breakthrough with my UIScrollView issue. Thank you!

  • Alexander says:

    Hi Mike,

    This was very helpful and gives a great understanding for a beginner like myself, however i am having challenges implementing it, in my case i am not using text fields or any other “static” element.

    I am trying to add a label which may contain from 2 lines to 100, then when i try to implement your code i can certainly scroll down but only to a certain point in which the text truncates. I am not sure what am i missing here.

    Thanks in advance.

  • Matt Durgavich says:

    Thank you so much! I was going nuts trying to figure out why my constraints, when the constants were modified, didn’t update frame positions of my components. Thanks a million.

  • Aaron says:

    Ahh great post but what about using the Stackview inside the Scrollview? I’ve been trying to do this and I’m going around in a circle known as “constraint hell”, you know, when you fix 5 constraint problems and wind up with 10 more after you’ve fixed them…

    • Mike Woelmer Mike Woelmer says:

      Hi Aaron,

      I haven’t tried a stack view inside the scrollview yet, but it should work. In fact you should be able to use a stack view as your container view. Make sure you have constraints from each edge of the stack view that connect to the scrollview. I’ll try it out later and see if it works.

  • TanTheMan says:

    How do I get rid of the errors after this step. “When finished, you will notice we are getting some Auto Layout errors. Without any controls inside the content view, or if there are no placeholder width and height constraints on the content view, the scroll view cannot determine the content size”.
    I’ve put content inside the content view but it’s still asking me to give Y constraint or height for my content view? Why?

    • Mike Woelmer Mike Woelmer says:

      Hi TanTheMan,

      You can pull my sample code from github to see how I have done my constraints. You have to make sure that you have connecting vertical constraints from one control to another that extend from the top of the container view to the bottom.

      –Mike.

  • Kakajan says:

    Hi, Mike, I download your sample code and compared with mine, everything is same. My view displays correctly on both horizontal and vertical layout. I have three labels designed vertically. Scroll view does not work when I try to scroll the view. It doesn’t scrolls down. Why?

  • Rupesh says:

    Very nice tutorial. Thanks for the information

  • Bipin maurya says:

    hello Mike Woelmer,

    this project layout is not working for iphone 6s plus.

  • john says:

    Great post. Everything works great except for one thing.
    I tried to play around with the example.
    Once I add a navigation controller, the Content View got push down in the Scroll view.
    No matter what I did, I can’t get it to align properly. (Ie. top of content view = top of scroll view)
    The easiest way to reproduce the issue is that, open your sample project and then select “Editor” from the menu and choose “Embed in ” –> “Navigation Controller”
    Any pointers would be greatly appreciated..
    Thank you so much in advance

    • Harsh Mehrotra says:

      Yes! You are right! I am also facing the same issue.

  • nono says:

    “The solution is to look outside the scroll view and attach an equal width constraint from the content view to the view controller’s main view.” Indeed there was a time when this was needed because some time ago if you set equal width between content view and the scrollview then Xcode showed ambiguous content size warrning. However it seems that in current version of Xcode you can simply set equal width between content view and scroll view (instead of main view as in this tutorial). Does anyone know if this is safe and if it works also in previous iOS version or should we still stick to the solution presented in this tutorial (that is equal width between content view and main view) if we need to support older iOS versions? It would be great if someone could clarify the difference.

  • Harsh Mehrotra says:

    Hi Mike Woelmer,
    I am facing issue when the content of my view is going beyond the height of the Scroll View.
    Suppose I have 100 Labels which I need to put on my scroll view vertically one after another. How it can be done?

    • Mike Woelmer Mike Woelmer says:

      Hi Harsh,

      You have a few options available to you.

      1. Layout all 100 labels in the storyboard. As I mentioned in my post, you can increase the visual size of your View Controller in the storyboard. To do this click on the view controller, select the size inspector and select Freeform size. Note, this does not change the size of the View Controller at runtime. This only allows you to layout all of your controls on the storyboard. Now 100 items is a crazy big number, so I would suggest some of the other options.

      2. Use a table view controller with dynamic cells. With that many labels, you probably have many of them that have a similar layout. This is the option I would pick.

      3. If a table view controller will not work, and you do not want to layout all of your controls on the storyboard, you can generate your UILabels and auto layout constraints dynamically.

  • Mikolaj says:

    Thx Mike,

    Playing with solution similar to yours (also based na Apple docs) I’ve noticed that line with scrollRectToVisible does nothing. You can comment it out and app still works properly and scrolls the content view (iOS 9.2).

    I found it while trying to scroll up the content view a little more and I couldn’t afford this by changing frame in the scrollRectToVisible call. Then I commented this line out and it still worked.

    I’ve checked it with your solution, just by commenting out this single line and it also works perfectly fine without this scrollRectToVisible call.

    Interesting, isn’t it? :)

  • Amalan says:

    Hi Sir!
    The Blog was helpful. I have a small Doubt, If i want to have a menu fixed on top how can i achieve it? In my scenario when i try to enter in a text field the menu also scrolls up. Is there a way to keep the menu positioned at the top fixed irrelevant of the keyboard appearing. :)

    • Mike Woelmer Mike Woelmer says:

      Hi Amalan,

      You can achieve what you want by not making the UIScrollView full screen. Attach your menu to the top of the main view and then attach the top of the UIScrollView to the bottom of your menu.

  • Peter Allday says:

    Really grateful, thank you.
    Every time I have to do this I struggle, but your one point of tying it to the size of the outside component is what I have been missing all these years.
    Really can’t thank you enough.
    Best regards
    Peter

  • Israel says:

    Thank you very much bro!! So useful tutorial!

  • Mark Reid says:

    Thanks for the clear article and also for keeping it up-to-date with the changes since it was originally written.

    This has given me the knowledge I needed about UIScrollView that scouring the Internet for two days hadn’t before now.

  • Bob Cowe says:

    Hi Mike.
    I have recently been trying this in iOS10 (Beta).
    However, when I do this part: “The solution is to look outside the scroll view and attach an equal width constraint from the content view to the view controller’s main view.” it ends up with a ScrollView which will not pass events through to the controls below. (I know, its unbelievable, but try it…)
    I’ve been trying multiple ways to solve that problem, but so far none of the tried and tested solutions are working.
    Are you able to suggest another way to force the autosize of the content view?
    Thanks
    Bob

    • James Scott says:

      Yep, I’m using XCode 8.1 and I’m still experiencing this!!! Anyone else? Please help…

  • noveleven says:

    Thank you very much, the sample code is very useful, you saved my day!

  • cboy says:

    Thanks buddy, I found really helpful content here.

    Keep it up and its really good work…..

  • chamanthula raju says:

    Hi Mike Woelmer,

    Actually when using scrollview in full of screen, it will work for all devices.
    But when I use scrollview from middle of the screen the scrolling is not working.When i click on textfield it works fine,but when i scrolling the view it scrolls till the visible elements only.
    Please give me solution of this problem.

  • Erik Fritts says:

    Thank you so much Mike your my hero. Boss irritating me, scrollview won’t cooperate with autolayout, everyones explanation vague as urinal water. I like things Barney style you are the man.

  • Mike says:

    Thank you so much Mike.
    I really found it helpful
    It will help me for sure.

  • Darshit says:

    Its helpful to me. you have a great logic to maintain view.
    Thank you.

  • azade says:

    hi.it was a great tutorial but unfortunately it doesn’t work on Xcode 9.2.scrollview works but text Fields went under keyboard and can’t animate to top

  • Comments are closed.