I have spent two days trying out the various solutions for Mixed and Pure Autolayout approaches to achieve what was a trivial scrollview setup prior to autolayout, and it\'s
Similar problem I'm having today with iOS 8.4, Xcode 6.4
There a view containing a scroll view, containing a contentView (UIView) containing subviews.
Everything is auto layout everywhere. The scrollview edges are pinned to the parent views edges with constraints. The content view edges are pinned to the scroll view edges with constraints.
Originally the content view would refuse to size as the full width of the scroll view. I had to add an additional constraint on the content view to have its width match the parent scroll view. Or I could set a contentView.centerX == scrollView.centerX constraint. Either one of those in addition to pinning the edges suddenly made the content view properly size.
// Either one of these additional constraints are required to get autolayout to correctly layout the contentView. Otherwise contentView size is its minimum required size
scrollView.addConstraint(NSLayoutConstraint(item: contentView, attribute: .CenterX, relatedBy: .Equal, toItem: scrollView, attribute: .CenterX, multiplier: 1.0, constant: 0))
scrollView.addConstraint(NSLayoutConstraint(item: contentView, attribute: NSLayoutAttribute.Width, relatedBy: .Equal, toItem: scrollView, attribute: .Width, multiplier: 1.0, constant: 0.0))
Pinning the edges of the content view to the scroll view using visual constraints of the form,
let cvConstraints = ["H:|[contentView]|", "V:|[contentView]|"]
I use a routine to iterate through the array and add them to the scrollView.
I faced a similar problem. I set every constrained and was always wondering why it still resizes some subviews. My solution was to set clipsToBounds to YES.
If like me you just use static content without counstraints inside the subview, like you can do like this:
override func viewDidLayoutSubviews() {
scrollView.contentSize = CGSizeMake(320, 800)
}
The pure autolayout approach works beautifully but it is quite a pain to get set up if you're migrating from non-autolayout. I've done it a few times now and I have a few general tips:
I assume you are running into issues with thecontentSize
. Check out this blog post on how to handle the contentSize
when using a "pure" AutoLayout approach. The gist of it is that your constraints implicitly define the content size. You NEVER set it explicitly when using AutoLayout. I've attached example project at the end of the blog post to demonstrate how it works
The following solution worked for me for scrollView with autolayout and without contentSize:
And you're done. Now, you can add any number of controls on this view and apply the constraints relevant to each other (which don't seem working without this view). If you don't want to use this view then you'll have to apply constraints for each control related to scrollView (not related to each other).
Critical. Let's say for clarity the UIScrollView is 1000 wide and 100 high. (In fact normally these values would be dynamic, of course, depending on the width of the device etc. But for now just say 1000 wide and 100 high.) Let's say you are doing a horizontal scroll. So put a UIView inside the UIScrollView. (That is the "content view".) Set all four constraints of the content view top, bottom, leading, trailing, to the scroll view. Make them all zero even if that seems wrong. Set the height of the content UIView to 100 and forget about that. Now: you want to scroll horizontally, so set the width of the content view to be let's say 1225.
Note that the width of the content view is now 225 bigger than the width of the parent scroll view. That's OK: in fact, you MUST do that. Note that
you would think you have to "match" the widths as you normally would. But if you do that, it will not work at all.
Interestingly, you can actually set the leading/trailing numbers to any positive value (try say "50") and it gives you kind of a margin of the bounce. (It often looks great: try it.) Any negative value on either end will "silently break".
Note that, infuriatingly, often Xcode (as of 7.3.1 anyway),
because it tries to automatically tally them for you. If so it will silently break. Set all four values to zero in the first instance. And set the width of the content view much wider than the "1000" in the example.
Edited: I've ended up with using UITableView instead of UIScrollView for most of my requirement. As tableView seems to me much more flexible and dynamic.