How to setup constraints so a view's width is 0 if it can't be at least a certain width

Viewed 164

I'm trying to create a launch screen storyboard (so no code) with a somewhat complicated layout.

The problem is that I need two views shown side by side (kind of like a split view controller). Here are the requirements:

  1. The left view's width should be half the width of the right view. In other words, the left view takes up the left 1/3 of the screen.
  2. The left view's width should be no more than 375 points. This takes precedence over the first constraint. In other words, the left view should try to take up the left 1/3 of the screen but be no wider than 375.
  3. The left view's width should be at least 340 points. If the width due to the first constraint would make it less than 340, it should be reduced to 0 and the right view should take up the full width of the screen. In other words, if the screen width is less than 1020, only the right view should be visible.

All three of these must be applied to the regular width size class.

I have the first two requirements working just fine. I can't figure out how to apply the 3rd requirement.

These are the constraints I have at the moment:

  • LeftView.top = SuperView.top
  • LeftView.bottom = SuperView.bottom
  • LeftView.leading = SuperView.leading
  • RightView.top = SuperView.top
  • RightView.bottom = SuperView.bottom
  • RightView.trailing = SuperView.trailing

Those pin the two views around the sides. The following additional constraints set the widths of the two views to meet my first two requirements:

  • LeftView.trailing = RightView.leading
  • LeftView.width = 0.5 * RightView.width @ 999
  • LeftView.width <= 375

With those in place you can see the results in various iPads.

On a 12.9" iPad in portrait you will see the left view taking up the left 1/3 of the screen and the right taking the right 2/3 of the screen. On a 12.9" iPad in landscape, the left view maxes out at 375 and the right view takes the rest of the screen. All good so far.

On a 9.7" iPad in landscape you see the left view taking the left 1/3 of the screen and the right view taking the right 2/3 of the screen. Again, good.

The problem I'm trying to solve starts with a 9.7" iPad in portrait. The left view is taking up 1/3 of the screen but it's really narrow. It's only 256 points wide. Since that is smaller than my desired minimum of 340, I don't want the left view to appear at all. The right view should fill the whole iPad.

Is there some combination of constraints, perhaps with various priorities, that can force the left view's width to 0 if it can't be at least 340?

As a side note, I have even different requirements for compact width but I have all of that working. It's just this one last requirement for different sized screens within the regular width size class that I need to solve.

1 Answers

Looks like I managed to achieve what you need. Tested it on iPad 9.7" and 12.9", works as expected. It's a bit of a mess, but it works.

The trick is to use additional view, which should be 0 points wide if screen is less then 1020 points, and 1 point wide otherwise (I'll refer to it as OnePixelWideView). Then make your LeftView.width == 375 * OnePixelWideView.width @ 999.

Another complication is that it will not work with LeftView.width = 0.5 * RightView.width @ 999, regardless of priority, but we can work around that by adding one more view with sides pinned to superview (I'll call it FullscreenView), and make LeftView.width <= 0.33 * FullscreenView.width

Here is a full list of horizontal constraints:

FullscreenView.leading = superview.leading
FullscreenView.trailing = superview.trailing

superview.trailing = OnePixelWideView.trailing + 1019
superview.leading = OnePixelWideView.leading @ 999
OnePixelWideView.width <= 1

LeftView.leading = superview.leading
LeftView.width <= 375
LeftView.width <= 0.33 * FullscreenView.width
LeftView.width = 375 * OnePixelWideView.width @999

RightView.leading = LeftView.trailing
RightView.trailing = superview.trailing

Here is a .storyboard content to play around.

Related