UIStackView Tutorial: Introducing Stack Views

Learn how to simplify your iOS layouts in iOS 11 with this UIStackView tutorial.

4.8/5 9 Ratings · Leave a Rating


  • Swift 4, iOS 11, Xcode 9
Update note: This tutorial has been updated to iOS 11, Xcode 9 and Swift 4 by Kevin Colligan. The original tutorial was written by Jawwad Ahmad.

We’ve all been there. There’s a new requirement and you need to add or remove a view at runtime, and also need to reposition adjacent views.

What approach do you take? Do you add outlets to constraints in your storyboard so that you can activate or deactivate certain ones? Or do you use a third party library? Or depending on the complexity maybe you do everything in code.

Maybe this time around your view hierarchy didn’t have to change at runtime, but you still had to figure out how to squeeze this one new view into your storyboard.

Did you ever end up just clearing all constraints and re-adding them from scratch because it was easier than performing painstaking constraints-surgery?

With the introduction of UIStackView, the above tasks become trivial. In this UIStackView tutorial, you’ll learn how stack views provide an easy way to lay out a series of views horizontally or vertically. You’ll learn how to get views to automagically adjust themselves to the available space by using properties such as alignment, distribution, and spacing. Enjoy :]

Note: This UIStackView tutorial assumes basic familiarity with Auto Layout. If you’re new to Auto Layout check out the Beginning Auto Layout video tutorial.

Getting started

In this UIStackView tutorial, you’ll work on an app called Vacation Spots. It’s a simple app that shows you a list of places to get away from it all.

But don’t pack your bags just yet, because there are a few issues you’ll fix by using stack views, and in a much simpler way than if you were using Auto Layout alone.

Start by downloading the starter project for this UIStackView tutorial. Open the project and run it on the iPhone 7 Simulator. You’ll see a list of places you can go on vacation.

uistackview tutorial

Go to the info view for London by tapping on the London cell.

At first glance, the view may seem okay, but it has a few issues.

  1. Look at the row of buttons at the bottom of the view. They are currently positioned with a fixed amount of space between themselves, so they don’t adapt to the screen width. To see the problem in full glory, temporarily rotate the simulator to landscape orientation by pressing Command-left arrow.

uistackview tutorial

  1. Tap on the Hide button next to WEATHER. It successfully hides the text, but it doesn’t reposition the section below it, leaving a block of blank space.

uistackview tutorial

  1. The ordering of the sections can be improved. It would be more logical if the what to see section was positioned right after the why visit section, instead of having the weather section in between them.
  2. The bottom row of buttons is a bit too close to the bottom edge of the view in landscape mode. It would be better if you could decrease the spacing between the different sections – but only in landscape mode.

Now that you have an idea of the improvements you’ll be making, it’s time to dive into the project.

Open Main.storyboard. The first time you do that, you’ll be asked to Choose an initial device view. This view has no effect at runtime — the view will resize for different devices — this just makes it a bit easier to work with the storyboard. Select the iPhone 7.

uistackview tutorial

You can change the view any time by clicking the View As: iPhone 7 link at the bottom left of the storyboard canvas.

uistackview tutorial

Now take a close look at the Spot Info View Controller scene. Whoa! What’s with all the colors?

uistackview tutorial

These labels and buttons have various background colors set that will be cleared at runtime. In the storyboard, they’re simply visual aids to help show how changing various properties of a stack view will affect the frames of its embedded views.

You don’t need to do this now, but if at any point you’d actually like to see the background colors while running the app, you can temporarily comment out the following lines in viewDidLoad() inside SpotInfoViewController.

// Clear background colors from labels and buttons
for view in backgroundColoredViews {
    view.backgroundColor = UIColor.clear

Also, any outlet-connected labels have placeholder text that’s set to the name of the outlet variable to which they are connected. This makes it a bit easier to tell which labels will have their text updated at runtime. For example, the label with text <whyVisitLabel> is connected to:

@IBOutlet weak var whyVisitLabel: UILabel!

Enough introduction, let’s get started!

Your first stack view

The first thing you’ll fix by using a stack view is the spacing between the bottom row of buttons. A stack view can distribute its views along its axis in various ways, and one of the ways is with an equal amount of spacing between each view.

Fortunately, embedding existing views into a new stack view is not rocket science. First, select all of the buttons at the bottom of the Spot Info View Controller scene by clicking on one, then Command-click on the other two:

uistackview tutorial

If the outline view isn’t already open, go ahead and open it by using the Show Document Outline button at the bottom left of the storyboard canvas:

uistackview tutorial

Verify that all 3 buttons are selected by checking them in the outline view:

uistackview tutorial

In case they aren’t all selected, you can also Command-click on each button in the outline view to select them.

Once selected, click on the new Stack button in the Auto Layout toolbar at the bottom right of the storyboard canvas:

uistackview tutorial

The buttons will become embedded in a new stack view:

uistackview tutorial

The buttons are now flush with each other – you’ll that fix shortly.

While the stack view takes care of positioning the buttons, you still need to add Auto Layout constraints to position the stack view itself.

When you embed a view in a stack view, any constraints to other views are removed. For example, prior to embedding the buttons in a stack view, the top of the Submit Rating button had a vertical spacing constraint connecting it to the bottom of the Rating: label:

uistackview tutorial

Click on the Submit Rating button to see that it no longer has any constraints attached to it:

uistackview tutorial

Another way to verify that the constraints are gone is by looking at the Size inspector (⌥⌘5):

uistackview tutorial

In order to add constraints to position the stack view itself, you’ll first need to select it. Selecting a stack view in the storyboard can get tricky if its views completely fill the stack view.

One simple way is to select the stack view in the outline view:

uistackview tutorial

Another trick is to hold Shift and Right-click on any of the views in the stack view, or Control-Shift-click if you’re using a trackpad. You’ll get a context menu that shows the view hierarchy at the location you clicked, and you simply select the stack view by clicking on it in the menu.

For now, select the stack view using the Shift-Right-click method:

uistackview tutorial

Now, click the Pin button on the Auto Layout toolbar to add constraints to it:

uistackview tutorial

First add a check to Constrain to margins. Then add the following constraints to the edges of your stack view:

Top: 20, Leading: 0, Trailing: 0, Bottom: 0

Double-check the numbers for the top, leading, trailing, and bottom constraints and make sure that the I-beams are selected. Then click on Add 4 Constraints:

uistackview tutorial

Now the stack view is the correct size, but it has stretched the first button to fill in any extra space:

uistackview tutorial

The property that determines how a stack view lays out its views along its axis is its distribution property. Currently, it’s set to Fill, which means the contained views will completely fill the stack view along its axis. To accomplish this, the stack view will only expand one of its views to fill that extra space; specifically, it expands the view with the lowest horizontal content hugging priority, or if all of the priorities are equal, it expands the first view.

However, you’re not looking for the buttons to fill the stack view completely – you want them to be equally spaced.

Make sure the stack view is still selected, and go to the Attributes inspector. Change the Distribution from Fill to Equal Spacing:

uistackview tutorial

Now build and run, tap on any cell, and rotate the simulator (⌘→). You’ll see that the bottom buttons now space themselves equally!

But there’s one more thing to consider. Build and run your app using the smaller iPhone SE simulator. Tap through to London and you’ll notice the Submit Rating is squashed.
uistackview tutorial

Fortunately, that’s an easy fix. Go back to the Attributes inspector. Change the Distribution from Equal Spacing to Fill Proportionally and add 10 for spacing.

uistackview tutorial

Now build and run one more time on the iPhone SE simulator and everything should look in order.

uistackview tutorial

Congratulations, you’ve built your first stack view!

uistackview tutorial

In order to solve this problem without a stack view, you would have had to use spacer views, one between each pair of buttons. You’d have to add equal width constraints to all of the spacer views as well as lots of additional constraints to position the spacer views correctly.

It would have looked something like the following. For visibility in the screenshot, the spacer views have been given a light gray background:

uistackview tutorial

This isn’t too much of an issue if you only have to do this once in the storyboard, but many views are dynamic. It’s not a straightforward task to add a new button or to hide or remove an existing button at runtime because of the adjacent spacer views and constraints.

In order to hide a view within a stack view, all you have to do is set the contained view’s hidden property to true and the stack view handles the rest. This is how you’ll fix the spacing under the WEATHER label when the user hides the text below it. You’ll do that a bit later in this UIStackView tutorial once you’ve added the weather section labels into a stack view.

Note: You now know how to specify the spacing between subviews in your stack. But what if you want different spacing after a specific subview? In iOS 11, you can do that with a new method, setCustomSpacing:afterView.

Converting the sections

You will convert all of the other sections in SpotInfoViewController to use stack views as well. This will enable you to easily complete the remaining tasks. You’ll convert the rating section next.

Rating section

Right above the stack view that you just created, select the RATING label and the stars label next to it:

uistackview tutorial

Then click on the Stack button to embed them in a stack view:

uistackview tutorial

Normally, your next step would be to add your stack view constraints. But there seems to be a bug in Xcode 9 beta 4 that makes it necessary to give your stack view a width before adding relative constraints. So click on the Pin button, give your stack view a width of 200 and click the “Add 1 Constraint” button.

Now click on the Pin button once again. Place a checkmark in Constrain to margins and add the following three constraints:

Top: 20, Leading: 0, Bottom: 20

uistackview tutorial

Now go to the Attributes inspector and set the spacing to 8:

uistackview tutorial

It’s possible you may see a Misplaced Views warning and see something like this in which the stars label has stretched beyond the bounds of the view:

uistackview tutorial

Sometimes Xcode may temporarily show a warning or position the stack view incorrectly, but the warning will disappear as you make other updates. You can usually safely ignore these.

However, to fix it immediately, click the Refresh Layout button right next to the stack view button.

uistackview tutorial

uistackview tutorial

Build and run to verify that everything looks exactly the same as before.

Unembedding a stack view

Before you go too far, it’s good to have some basic “first aid” training. Sometimes you may find yourself with an extra stack view that you no longer need, perhaps because of experimentation, refactoring or just by accident.

Fortunately, there is an easy way to unembed views from a stack view.

First, you’d select the stack view you want to remove. Then hold down the Option key and click on the Stack button. The click Unembed on the context menu that appears:

uistackview tutorial

Another way to do this is to select the stack view and then choose Editor \ Unembed from the menu.

Your first vertical stack view

Now, you’ll create your first vertical stack view. Select the WHY VISIT label and the <whyVisitLabel> below it:

uistackview tutorial

Xcode will correctly infer that this should be a vertical stack view based on the position of the labels. Click the Stack button to embed both of these in a stack view:

uistackview tutorial

The lower label previously had a constraint pinning it to the right margin of the view, but that constraint was removed when it was embedded in the stack view. Currently, the stack view has no constraints, so it adopts the intrinsic width of its largest view.

With the stack view selected, click on the Pin button. Checkmark Constrain to margins, and set the Top, Leading and Trailing constraints to 0.

Then, click on the dropdown to the right of the bottom constraint and select WEATHER (current distance = 20):

uistackview tutorial

By default, constraints are shown to the nearest neighbor, which for the bottom constraint is the Hide button at a distance of 15. You actually needed the constraint to be to the WEATHER label below it.

Finally, click Add 4 Constraints. You should now see the following:

uistackview tutorial

You now have an expanded stack view with its right edges pinned to the right margin of the view. However, the bottom label is still the same width. You’ll fix this by updating the stack view’s alignment property.

Alignment property

The alignment property determines how a stack view lays out its views perpendicular to its axis. For a vertical stack view, the possible values are Fill, Leading, Center, and Trailing.

The possible alignment values for a horizontal stack view differ slightly:

uistackview tutorial

It has .top instead of .leading and has .bottom instead of .trailing. There are also two more properties that are valid only in the horizontal direction, .firstBaseline and .lastBaseline.

Select each value to see how it affects the placement of the labels for the vertical stack view:


uistackview tutorial


uistackview tutorial

uistackview tutorial


uistackview tutorial

When you’re done testing each value, set the Alignment to Fill:

uistackview tutorial

Then build and run to verify that everything looks good and that there are no regressions.

Specifying Fill means you want all the views to completely fill the stack view perpendicular to its axis. This causes the WHY VISIT label to expand itself to the right edge as well.

But what if you only wanted the bottom label to expand itself to the edge?

For now, it doesn’t matter since both labels will have a clear background at runtime, but it will matter when you’re converting the weather section.

You’ll learn how to accomplish that with the use of an additional stack view.

Convert the “what to see” section

This section is very similar to the previous one, so the instructions here are brief.

  1. First, select the WHAT TO SEE label and the <whatToSeeLabel> below it.
  2. Click on the Stack button.
  3. Click on the Pin button.
  4. Checkmark Constrain to margins, and add the following four constraints:
Top: 20, Leading: 0, Trailing: 0, Bottom: 20
  1. Set the stack view’s Alignment to Fill.

Your storyboard should now look like this:

uistackview tutorial

Build and run to verify that everything still looks the same.

This leaves you with just the weather section left.

Convert the weather section

The weather section is more complex than the others due to the inclusion of the Hide button.

One approach you could take would be to create a nested stack view by embedding the WEATHER label and the Hide button into a horizontal stack view, and then embedding that horizontal stack view and the <weatherInfoLabel> into a vertical stack view.

It would look something like this:

uistackview tutorial

Notice that the WEATHER label has expanded to be equal to the height of the Hide button. This isn’t ideal since this will cause there to be extra space between the baseline of the WEATHER label and the text below it.

Remember that alignment specifies positioning perpendicular to the stack view. So, you could set the alignment to Bottom:

uistackview tutorial

But you really don’t want the height of the Hide button to dictate the height of the stack view.

The actual approach you’ll take is to have the Hide button not be in the stack view for the weather section, or any other stack view for that matter.

It will remain a subview of the top-level view, and you’ll add a constraint from it to the WEATHER label — which will be in a stack view. That’s right, you’ll add a constraint from a button outside of a stack view to a label within a stack view!

Select the WEATHER label and the <weatherInfoLabel> below it:

uistackview tutorial

Click on the Stack button:

uistackview tutorial

Click on the Pin button, checkmark Constrain to margins and add the following four constraints:

Top: 20, Leading: 0, Trailing: 0, Bottom: 20

Set the stack view’s Alignment to Fill:

uistackview tutorial

You need a constraint between the Hide button’s left edge and the WEATHER label’s right edge, so having the WEATHER label fill the stack view won’t work.

However, you do want the bottom <weatherInfoLabel> to fill the stack view.

You can accomplish this by embedding just the WEATHER label into a vertical stack view. Remember that the alignment of a vertical stack view can be set to .leading, and if the stack view is stretched beyond its intrinsic width, its contained views will remain aligned to its leading side.

Select the WEATHER label using the document outline, or by using the Control-Shift-click method:

uistackview tutorial

Then click on the Stack button:

uistackview tutorial

Set Alignment to Leading, and make sure Axis is set to Vertical:

uistackview tutorial

Perfect! You’ve got the outer stack view stretching the inner stack view to fill the width, but the inner stack view allows the label to keep its original width!

Build and run. Why on earth is the Hide button hanging out in the middle of the text?

uistackview tutorial

It’s because when you embedded the WEATHER label in a stack view, any constraints between it and the Hide button were removed.

To add new constraints Control-drag from the Hide button to the WEATHER label:

uistackview tutorial

Hold down Shift to select multiple options, and select Horizontal Spacing and Baseline. Then click on Add Constraints:

uistackview tutorial

Build and run. The Hide button should now be positioned correctly, and since the label that is being set to hidden is embedded in a stack view, pressing Hide hides the label, and adjusts the views below it — all without having to manually adjust any constraints.

uistackview tutorial

Now that all the sections are in unique stack views, you’re set to embed them all into an outer stack view, which will make the final two tasks trivial.

Top-level stack view

Command-click to select all five top-level stack views in the outline view:

uistackview tutorial

Then click on the Stack button:

uistackview tutorial

Click the Pin button, checkmark Constrain to margins add constraints of 0 to all edges. Then set Spacing to 20 and Alignment to Fill. Your storyboard scene should now look like this:

uistackview tutorial

Build and run:

uistackview tutorial

Whoops! Looks like the hide button lost its constraints again when the WEATHER stack view was embedded in the outer stack view. No problem, just add constraints to it again in the same way you did before.

Control-drag from the Hide button to the WEATHER label, hold down Shift, select both Horizontal Spacing and Baseline. Then click on Add Constraints:

uistackview tutorial

Build and run. The Hide button is now positioned correctly.

Repositioning views

Now that all of the sections are in a top-level stack view, you’ll modify the position of the what to see section so that it’s positioned above the weather section.

Select the middle stack view from the outline view and drag it between the first and second view.

Note: Keep the pointer slightly to the left of the stack views that you’re dragging it between so that it remains a subview of the outer stack view. The little blue circle should be positioned at the left edge between the two stack views and not at the right edge:

uistackview tutorial

And now the weather section is third from the top. If the Hide doesn’t move along with the weather section, click on the Refresh Layout button.

uistackview tutorial

The Hide button will now be back in the correct position:

uistackview tutorial

Granted, repositioning the view with Auto Layout and re-adding constraints would not have been the most difficult thing you’ve ever done, but didn’t this feel oh-so-much nicer?

Size class based configuration

Finally, you can turn your attention to the one remaining task on your list. In landscape mode, vertical space is at a premium, so you want to bring the sections of the stack view closer together. To do this, you’ll use size classes to set the spacing of the top-level stack view to 10 instead of 20 when the vertical size class is compact.

Select the top-level stack view and click on the little + button next to Spacing:

uistackview tutorial

Choose Any Width > Compact Height and select Add Variation

uistackview tutorial

And set the Spacing to 10 in the new wAny hC field:

uistackview tutorial

Build and run. The spacing in portrait mode should remain unchanged. Rotate the simulator (⌘←) and note that the spacing between the sections has decreased and the buttons now have ample space from the bottom of the view:

uistackview tutorial

If you didn’t add a top-level stack view, you still could have used size classes to set the vertical spacing to 10 on each of the four constraints that separate the five sections, but isn’t it so much better to set it in just a single place?

You have better things to do with your time, like animation!


Currently, it’s a bit jarring when hiding and showing the weather details. You’ll add some animation to smooth the transition.

Stack views are fully compatible with the UIView animation engine. This means that animating the appearance/disappearance of an arranged subview, is as simple as toggling its hidden property inside an animation block.

It’s time to write some code! Open SpotInfoViewController.swift and take a look at updateWeatherInfoViews(hideWeatherInfo:animated:).

You’ll see this line at the end of the method:

weatherInfoLabel.hidden = shouldHideWeatherInfo

Replace it with the following:

if animated {
    UIView.animate(withDuration: 0.3) {
        self.weatherInfoLabel.isHidden = shouldHideWeatherInfo
} else {
    weatherInfoLabel.isHidden = shouldHideWeatherInfo

Build and run, and tap the Hide or Show button. Doesn’t the animated version feel much nicer?

In addition to animating the hidden property on views contained within the stack view, you can also animate properties on the stack view itself, such as alignment, distribution, spacing and even the axis.

Where to go from here?

You can download the completed project here.

In this UIStackView tutorial, you learned a lot about stack views as well as the various properties that a stack view uses to position its subviews. Stack views are highly configurable, and there may be more than one way achieve the same result.

The best way to build on what you’ve learned is to experiment with various properties yourself. Instead of setting a property and moving on, see how playing with the other properties affects the layout of views within the stack view.

In the meantime, if you have any questions or comments about this UIStackView tutorial or Stack Views in general, please join the forum discussion below!

Average Rating


Add a rating for this content

9 ratings