Laying out views in a storyboard turns sometimes into a complex task due to the sheer amount of constraints that need to be dealt with to achieve the desired layout. For this purpose, there is UIStackView in iOS9 that handles the setup of the necessary constraints for its subviews.
Stackviews are configured mainly via 4 properties
If views need to be laid out along the X-Axis choose Horizontal, if along the Y-Axis choose Vertical. The options available in distribution and alignment are depending on this setting
Available options are left, centered, right & filled for horizontal stackviews and top, centered, bottom & filled for vertical stackviews. 'filled' means that a stackview's contentview's width or height is going to equal its stackview's width or height.
In an ideal world a stackview's subviews widths or heights add up nicely to its total widht/height. But since we are not living in an ideal world and hence have to deal with adaptive view layouts two cases basically need to be considered:
The accumulated sum of a stackview's views width/height is
a) smaller than its total width/height. This is called 'underflowed'.
b) larger than its total width/height. This is called 'overflowed'.
Since all views in a stackview are treated equally a subview's size or offset to its adjacent view needs to grow if underflowed or needs to shrink if overflowed.
This determines the distance between 2 adjacent views. Mind that this might be ignored depending on what has been selected in distribution.
Ok, now we know what can be configured in a stackview but how do we set it up? Let's look at how to do this in a storyboard first. It's best to look at a stackview not as an actual view but for what it really is: a layout helper class. Add stackviews where needed when all the actual views have already been added to the viewcontroller and roughly moved to their intended position. Then adding a stackview is quite easy since storyboards have a dedicated stackview button (see picture below) that embeds all selected views in them. Depending on the selection, horizontal or vertical, the resulting stackview will initialize its axis property accordingly. What remains to be adjusted are the remaining properties listed above. It couldn't be easier. A good example for this approach can be seen in Apple's WWDC video (roughly 3 minutes into the video).
All this can be done of course programmatically as well. For this however a basic understanding of a stackview's subview management is required.
Since a stackview is a view, it has of course a subview property. For its actual subview layout a stackview however considers another property called arrangedSubviews. ArrangedSubviews is a subset of subviews. So when adding views to a stackview via addArrangedSubviews, they will be added to subviews as well.
Adding a view to a stackview via addSubview is always wrong since it will keep the view from participating in a stackview's layout process. A view added this way will of course be shown but not properly laid out. Having said this, let's get down to business and write some some actual code:
//: Create a StackView
let stackView = UIStackView(frame: .zero)
stackView.axis = .Horizontal
stackView.distribution = .Fill
stackView.spacing = 20
stackView.alignment = .Center
stackView.translatesAutoresizingMaskIntoConstraints = false
//: Setup Stackview constraints, create a label, a sample View & a Switch
//: Add Views to stackview
The complete code can be found here.
By the way to remove a view from a stackview it is sufficient to set its hidden flag. And as you can see below, this can be nicely animated as well if need be.
There is no doubt that UIStackview is going to improve our day-to-day work with autolayout. Sure, it's not going to be a solution for all layouts but for a lot of layouts it will be and those can be implemented a lot faster now.
On a personal note I started to wonder if it was necessary to implement UIStackView as a view. Being a pure layout management helper class and hence not directly contributing to the UI rendering doesn't make me think that this was the right choice. UILayoutGuide for example had been added since it is more efficient than UIView for dealing with layout issues. Why not do the same with stackviews as well? Or is UILayoutGuide's absence from the storyboard toolbox a hint that for working with a class in the storyboard it has to inherit from UIView?