Fluid Layouts with Auto Layout, Size Classes, Spacer Views, and Constraint Priorities

I came across a problem the other day with the “compact x any” size class in iOS 8 & Xcode 6. I was creating a layout for the size class which is supposed to cover the iPhone 4S 3.5-inch screen all the way up to the iPhone 6 4.7-inch screen. However, this became difficult to do well because what looked good on a small screen (like the 3.5-inch) did not look good on the large screen (4.7-inch screen). Or what looked good on a bigger screen, the content did not fit on the smaller screen.

So, I started playing around with how to create a fluid layout to make this work and it turned out to be much more difficult than I anticipated. So, I thought I’d share an example of how I did it.

I’m going to show you how to create a fluid layout using Xcode 6 in the compact-any size class which works for all compact width layouts such as the 3.5-inch iPhone 4S all the way up to the 4.7-inch iPhone 6. I will show you how to create a fluid layout for a form for this size class so that, for example, when we’re on the iPhone 3.5 inch, it’s a compact form (see pic below)fluid layout initial setup, but when we go up to 4.7-inch iPhone 6, the form will expand and fill the entire screen (see pic below). fluid_layout_iphone_6_size We will use spacer views to make this form expand out to fill this entire screen.

In this form, you can see we have some labels and then some text fields. But what you need to know is that we also have an encompassing view surrounding each of those.encompassing views So, each of these fields and labels has an encompassing view which then has some constraints on it to their neighboring-sibling views and labels.

Ok, now that you know that. I’ll show you how we can add spacer views to make this form fluid.

Auto Layout Spacer Views

First, select all of the labels and text fields (and their encompassing views) and slide them down to make room for a spacer view underneath the header label.fluid layouts create space From the object collection in the right menu, search for a plain “view”. Scroll down and select a plain “view” from the collection and drag and drop it onto the storyboard.select view We’re going to need re-size this. We’re going to keep it 200 points wide. Go up to the size inspector and change the height to just 10. change height of spacer viewReposition the view just below the first label.reposition spacer view Now, we need to set up our constraints.

Auto Layout Constraints

The first constraint that we’re going to set up is a vertical constraint to the first label. So, hold down ctrl + click and drag to the first label and select “vertical spacing” create vertical spacing constraint Next, set up a center horizontally container constraint. This is going to make the spacer view center horizontally with the rest of these labels and fields. Create another vertical spacing constraint with the next view that encompasses the first label and text field. create_constaint_with_encompassing_view Then, create constraints for the width and the height. autolayout_create_height_and_width_constraint

So now, we have all the constraints for this spacer view, but we need to change the constants on some of the constraints. To do that, select the spacer view and then select the size inspector from the menu of the right.

The first constant we’re going to change is the first vertical spacing constraint. Select the constraint and change the constant to zero.change_autolayout_constraint_constant Then, change the bottom space constraint to zero as well. And you can see now that all the space that exist now between the first label and the next encompassing view is the height of our spacer view.

Auto Layout Contraint Priorities

The last thing we need to do for this spacer view is set the priority of this height constraint. To change the priority, select the height constraint and hit “edit” and under the priority selection, select 750.change_auto_layout_constraint_priority So, slightly less priority than all the other constraints. And that’s it, that’s all we need to do for this first spacer view.

So, copy the spacer view by holding down the option key and dragging it down below the first form field. copy_and_reposition_second_spacer_view

Now, we need to do the same thing with this spacer view as we did with the first one. Set a vertical constraint to the encompassing view of the first form field. Then, add a vertical spacing constraint to the next encompassing view of the next form field. Add a constraint to make sure it’s centered horizontally and it’s all set, it should have already copied over the width and height constraints.

We need to change the constants on the constraints once again. Select the spacer view and go to the size inspector and change the vertical spacing constraints’ constants to zero.

We also need to do something a little bit different with the height constraint. We’re actually going to remove the height constraint. Open up the document outline for the storyboard. open_document_outline Go back over to our height constraint and select it and that will show selected in the document outline, so we’ll select it and just hit delete and remove that.remove_auto_layout_height_constraint So, now that constraint is gone. Select the second spacer view again, and hold down ctrl, click and drag and select the first spacer view and set the constraint as equal heights. set_auto_layout_equal_heights_constraint

The idea here is that we’ll create the spacer views that will then expand equally out as the screen gets larger. So, we don’t want them to be different heights or expand the different sizes, we want them all to be equal size. So, we’re going to set them as equal heights. And that’s it! That’s all we need for this second spacer view.

You will need to setup a spacer view in between each encompassing view of the form. Because of the rest of the spacer views are pretty much the same as the first and the second one, I’m just going to go ahead and skip to the end of this so that all the spacer views will be set up. I will show you the last step that we need to do in order to create our fluid layout. Here’s what the layout looks like with all the spacer views setup. spacer_views_all_setup

So, the last step we need to do, select the “sign up” button and control drag and create one more constraint by selecting the controller’s view and select “bottom space to bottom layout guide”. add_auto_layout_bottom_space_constraint So now we have created this constraint for this button. We have this constraint now, but we want the “sign up” button constrained, so that’s a little bit closer to the bottom of the screen. The way we can do that is selecting the new constraint and updating this constant to be a smaller number than 209, that’s automatically set to right now. Set the constant on this constraint to 50. hange_auto_layout_constraint_constant_to_50 You can see the form now expands. And you can see that is expanding because the height of this spacer views is expanding as well and they’re expanding equally. And that’s because the constraint priority that we set up earlier for the height of the spacer view. fluid_form_with_spacer_views_with_background_color

Because that constraint has a lower priority than the rest of the constraints that were set up, the constraint breaks when it expands and contracts for the different sizes of the screens. If your spacer views have a background color, you can go ahead and remove the color from this spacer views. Now, you can see how the form expands and contracts in the different fields have equal spacing in between them, it expands and contracts to fill out the different screens. fluid_form_with_spacer_views_without_background_color

So, that’s it! That’s how we can create a fluid layout using spacer views and constraint priorities in Xcode 6 with size classes. So if you have any questions, feel free to leave a comment and I will try to answer them.

Freelance Elixir & Ruby on Rails Developer Hey, I’m Adam. I’m guessing you just read this post from somewhere on the interwebs. Hope you enjoyed it.

You can also follow me on the Twitters at: @DeLongShot