Stack View Custom Spacing

When Apple introduced stack views in iOS 9 they made it much easier to use Auto Layout by reducing the number of constraints you needed to create yourself for many common layouts. One edge case that was not well covered was the need for custom spacing between views. You could do it by nesting stack views but that always seemed an unnecessary complication. In iOS 11 you can create stack views with custom spacing between views.

The Problem

Here is the example layout I want to create:

Variable space layout

I have a total of five labels. A header label with a larger font size, three labels and small font size footer. The three middle labels have spacing of 8 points but I want the header and footer to have 32 points of spacing.

This vertical arrangement of views is perfect for a UIStackView apart from the spacing. The spacing property of a stack view applies equally to the arranged subviews.

Stacking Stacks

One way to create the layout without needing spacer views is to embed an inner stack view.

Inner Stack View

The inner stack view with the three labels has 8 point spacing and the outer stack view has 32 points of spacing. This works but can quickly get messy. For example, if I wanted different spacing for the header and footer.

Custom Spacing (iOS 11)

New in iOS 11 it is possible to customize the spacing after any of the arranged subviews of a stack view. Assuming we have our labels already created the code to setup the stack view might be something like this:

let stackView = UIStackView(arrangedSubviews: [headerLabel, topLabel, middleLabel, bottomLabel, footerLabel])
stackView.axis = .vertical
stackView.alignment = .fill
stackView.spacing = 8.0

This gives us 8 points of spacing between the arranged subviews. To get the extra spacing after the header label and before the footer label:

// iOS 11 only
stackView.setCustomSpacing(32.0, after: headerLabel)
stackView.setCustomSpacing(32.0, after: bottomLabel)

Notes:

  • You always specify the spacing after the arranged subview. There is no method to specify spacing before a view.
  • There is no way to specify this custom spacing in Interface Builder. You need to do it in code.
  • When you remove the subview from the stack view the system removes the custom spacing.

Standard and Default Spacing

There are two new type properties on the UIStackView class in iOS 11 that define default and system spacing:

class let spacingUseDefault: CGFloat
class let spacingUseSystem: CGFloat

You cannot rely on the values that these properties return. The actual values are tokens used to ask for the default or system spacing. System spacing seems to give 8 points of spacing on an iPhone but again you should not rely on the actual value.

You can use these to set or reset the custom spacing after a view. For example to use the system defined spacing after the top label:

stackview.setCustomSpacing(UIStackView.spacingUseSystem, after: topLabel)

To reset the spacing after this label back to the value of the spacing property (removing the custom spacing):

stackview.setCustomSpacing(UIStackView.spacingUseDefault, after: topLabel)