1
[_contentView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.mas_equalTo(_scrollTabs);
    make.height.mas_equalTo(_scrollTabs);
}];

[_scrollTabs mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.mas_equalTo(self);
}];

self is a custom view. I set the constraints like this. Am I doing something wrong? Thanks!

Jiang Yong
  • 11
  • 2
  • What you are trying to achieve ? – CodeChanger Jan 23 '17 at 06:59
  • @CodeChanger, I want it to scroll only horizontally, so I set a content view for the scroll view(`_scrollTabs`), and make its height equals to scrollview. Did I miss some constraints to make it work? – Jiang Yong Feb 07 '17 at 03:44
  • @Rob, Thanks for the sample code mentioned above. I know something about Autolayout with scroll view. I am trying to use a content view to hold all subviews I want to display in the scroll view(`_scrollTabs`), and I've set all constaints of all these subviews to `_contentView`. Is it enough to calculate the `contentSize` of `_scrollTabs`? – Jiang Yong Feb 07 '17 at 03:54
  • Are you saying that it's scrolling incorrectly (i.e. you don't have any content below 44) or are you saying that it's scrolling absolutely correctly, but that the `contentSize` appears to be incorrect? If the latter, at what point are you pausing execution and looking at `contentSize`? I assume you're not looking at it in `viewDidLoad`... – Rob Feb 09 '17 at 16:16

1 Answers1

0

Bottom line, if you unambiguously define the constraints between a content view and the scroll view (which will define the contentSize pursuant to TN2154) and then unambiguously define the constraints between the content view and its subviews, then, yes, it will correctly define the size of the scroll view's contentSize.

I would suggest using the view debugger, enter image description here, and look at the constraints in the right panel:

view debugger

In the particular screen snapshot, I've selected the third subview (dark blue) inside the content view inside the scroll view, and it tells us that the active constraints are:

  • offset 10 from leading edge of container (green)
  • offset 10 from trailing edge of container (green)
  • offset 10 from the subview above (dark red)
  • fixed height of 200 (I do this because this has no implicit height)
  • a width of the main view (bright red) less 20 (so that it occupies an appropriate amount of horizontal space, again because there is no implicit width)
  • offset 10 from the subview below (light blue)

So, you just click on your various subviews and the container, and confirm that the constraints are precisely what you intended. It's all to easy to miss a constraint and/or fail to activate one, and the whole thing falls apart.

By the way, sometimes it's not obvious what views the constraints are between, but if you tap on the constraints button, enter image description here, when a view is selected, it will highlight just the views to which you have constraints (in this example, to the content view, to the subviews above and below, and the main view; since neither the scroll view (yellow) nor the first subview (purple) have any constraints to this third subview, so you just see their wire-frame, not their content):

enter image description here


Note, this is an example, I thought that I'd show you the constraints I used so that auto layout can correctly calculate the contentSize based upon a content view and subviews with fully satisfied, unambiguous constraints:

let contentView = ContentView()
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.backgroundColor = randomColor()
scrollView.addSubview(contentView)

NSLayoutConstraint.activate([
    contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
    contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
    contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
    contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor)
])

var previousView: UIView?

for _ in 0 ..< 4 {
    let subview = SomeSubview()
    subview.translatesAutoresizingMaskIntoConstraints = false
    subview.backgroundColor = self.randomColor()
    contentView.addSubview(subview)

    NSLayoutConstraint.activate([
        subview.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10),
        subview.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10),
        subview.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -20),
        subview.heightAnchor.constraint(equalToConstant: 200)
    ])

    if previousView != nil {
        subview.topAnchor.constraint(equalTo: previousView!.bottomAnchor, constant: 10).isActive = true
    } else {
        subview.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10).isActive = true
    }

    previousView = subview
}

previousView?.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10).isActive = true

What strikes me odd in your example is that you are setting both edges (which I assume is setting the top, bottom, leading, and trailing constraints) and height. Setting the height of the content view is not needed. You can just define the edges and you should be good. The height is dictated by the constraints of its subviews.

If your subviews appear to be laid out correctly but your scroll view's contentSize is not getting set correctly, then the culprit may be a missing bottom constraint between the last subview and your content view.

If you're still having problems, I'd suggest you create a simplified, yet complete example of your problem. The code that you've shared is insufficient. But we don't want to see all of your code nor your specific UI, either. Instead, create a stand-alone simplified example that manifests the problem you describe. Only if we can reproduce your problem can we help you solve it.

Community
  • 1
  • 1
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Thanks for your help! Sorry for my mistake as a nood to Stackoverflow! An example will be presented lately. As you suggested, I check the view debugger, then print the description of my scroll view, it says `Printing description of $63: ; layer = ; contentOffset: {0, 0}; contentSize: {308.5, 44}>`. It seems that the height of the `contentSize` is equal to the height of the `frame`. But it still can scroll vertically. – Jiang Yong Feb 09 '17 at 03:02
  • I know what is happening now. I put the scroll view just beneath the navigation bar, and I forgot to set the `automaticallyAdjustsScrollViewInsets` to `NO`. So this stupid problem happened.... – Jiang Yong Feb 10 '17 at 08:17