3

I have a view which is correctly displayed on an iPhone 6 screen, but needs scrolling on an iPhone 5 screen. I am trying to change some Auto Layout constraint to remove the need to scroll on the latter.

Here is an attempt to explain my situation visually: enter image description here

The first 2 screenshots are the existing situations on an iPhone 6 and iPhone 5. The third one is what I am trying to achieve (on iPhone 5 only).

I wrote the following Auto Layout contraints, but I am missing something here:


[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=25,<=50)-[blueView]-(>=25,<=50)-[redView]-5-|"
                                                             options:0
                                                             metrics:nil
                                                               views:nameMap]];

Should Hugging and/or Compression Resistance be involved here? In what way?


Edit to show more of my actual code:

[self addSubview:loginNSignupScrollView];
[self.loginNSignupScrollView addSubview:logoImageView];
[self.loginNSignupScrollView addSubview:horizontalScrollView];
[self.loginNSignupScrollView addSubview:appVersionLabel];
[self.horizontalScrollView addSubview:loginView];

[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[loginNSignupScrollView]|" options:0 metrics:nil views:nameMap]];

[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[loginView(==350)]" options:0 metrics:nil views:nameMap]];

[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=30,<=60)-[logoImageView(==35)]-(>=25,<=50)-[horizontalScrollView]-30-[appVersionLabel]-5-|" options:0 metrics:nil views:nameMap]];

[self addConstraint:[NSLayoutConstraint constraintWithItem:self.horizontalScrollView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:0.0 constant:350]];

Pierre Espenan
  • 3,996
  • 5
  • 33
  • 51
  • Do you have other constraints that you have not shown? - Are you getting any messages in the Console? – matt Nov 13 '15 at 15:55
  • @matt please see my edit. I don't get any complaints from the Auto Layout engine in the console. – Pierre Espenan Nov 13 '15 at 16:05
  • Ah. So all this is happening inside a scroll view. Do you know how auto layout works with views inside scroll views? It works in a very special way. Do you know about that? Also, what are all these extra views? They are not in your screen shots. And where are your horizontal constraints? And how is the scroll view _itself_ being positioned? – matt Nov 13 '15 at 16:11
  • I did my best to simplify my case to the minimum needed. Maybe I over-simplified it. About the behavior of Auto Layout within a scrollview: I know about it, but didn't think it could be the issue here. Mmmh, let me have a look. The scrollview itself is being positioned using `@"H:|[loginNSignupScrollView]|"` and `@"V:|[loginNSignupScrollView]|"` – Pierre Espenan Nov 13 '15 at 16:17

2 Answers2

6

As you know, scroll views are special because, if you use auto layout inside them, the content size (the size of the scrollable content) is determined by the constraints from the inside out. Thus, you cannot directly do what you're trying to do. A better strategy is:

  • The scroll view, pinned to the superview (the main view)

  • A blank content view inside the scroll view, pinned to the scroll view with zero constants

  • Everything else, inside the content view

Once you've set that up, two good things happen:

  • The size of the content view is the scroll view's contentSize. So all you have to do is set that explicitly. A reasonable approach might be to set it in code in viewDidLayoutSubviews; that is the earliest that the true final interface size is known.

  • The constraints of the content view's subviews become ordinary constraints, positioning them from the outside in as usual, based on the content view's size — which, as we have just said, you are setting explicitly.

Using that sort of strategy, I achieved this (4s and 6s simulators, respectively), which seems to be at least the kind of thing you're after; observe that we are indeed in a scroll view, though you can't tell from the screen shots:

enter image description here

enter image description here

It isn't totally identical to your screen shots because it wasn't clear to me what you were really after, so I allowed the white spaces to grow/shrink equally while keeping the view heights constant; it may be that you wanted the red view height to grow on the larger screen. But that's a minor quibble, I think.

The only code I used was to set the size of the content view, which (as I said) is the same as setting the scroll view's contentSize:

NSLayoutConstraint.activateConstraints([
    self.contentView.widthAnchor.constraintEqualToConstant(
        self.view.bounds.size.width),
    self.contentView.heightAnchor.constraintEqualToConstant(
        self.view.bounds.size.height),
])
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • That's indeed probably the best approach here. I will try that out. What do you mean by "with zero constants" ? – Pierre Espenan Nov 13 '15 at 16:27
  • Constraints have `constant` properties. Your own code contains an example. – matt Nov 13 '15 at 16:37
  • Ah yeah ofc, me stoopid. – Pierre Espenan Nov 13 '15 at 16:38
  • Updated my answer with screen shots showing that this strategy will probably work for you. – matt Nov 13 '15 at 17:34
  • Could you please share some of your code? I still can't manage to allow the white spaces to grow/shrink. Using `V:|-(>=30,<=100)-[logoImageView(==35)]-(>=25,<=100)-[horizontalView(==350)]|`, the white space are always sized to the smallest possible values (30 and 25). – Pierre Espenan Nov 16 '15 at 11:31
  • I may have misunderstood the problem. I thought the issue was to get the _bottom_ of the lower view (your red view) to be within the window. So my only code is to supply constraints that set the size of the content view; I've added that code to my answer. – matt Nov 16 '15 at 14:47
  • As I explained in my answer, I wasn't entirely sure what you were after (your proposed constraints made no sense to me), so I just constrained the white spaces to be equal, thus positioning the blue view nicely between the top of the screen and the top of the red view, while holding the height of the red view (and the blue view) constant. I admitted in my answer that this might not be quite the same as what you wanted. – matt Nov 16 '15 at 14:55
  • Ah, communication is hard :) Still, let me some time to have a look at your updated answer. It may be what I am trying to do. – Pierre Espenan Nov 16 '15 at 15:15
0

I think you can pin your bottom view with bottom layout by some constant value so that bottom view will always keep diatance by that constant value from bottom.

Abhishek
  • 509
  • 3
  • 12