UIStackView
UIStackView is a UIKit class that simplifies the layout of multiple views by arranging them in a linear stack, either horizontally or vertically. Introduced in iOS 9, it is a subclass of UIView and leverages Auto Layout to manage the positioning and sizing of its arranged subviews. This document covers the key properties, methods, and usage of UIStackView, along with examples and best practices.
Overview of UIStackView
UIStackView provides an efficient way to create layouts by automatically managing Auto Layout constraints for its arranged subviews. It is ideal for organizing groups of views, such as buttons, labels, or text fields, in a row or column, and supports dynamic content changes, such as adding or removing views.
Creating a UIStackView
You can create a UIStackView programmatically or via Interface Builder (storyboards/xibs).
Programmatic Example:
import UIKit
let stackView = UIStackView()
stackView.axis = .vertical
stackView.spacing = 10
stackView.alignment = .center
stackView.distribution = .equalSpacing
view.addSubview(stackView)Key Properties of UIStackView
Below are the most commonly used properties of UIStackView:
| Property | Type | Description |
|---|---|---|
arrangedSubviews | [UIView] | The array of views managed by the stack view (read-only). |
axis | UILayoutConstraintAxis | The orientation of the stack: .horizontal or .vertical. |
spacing | CGFloat | The spacing between arranged subviews. |
distribution | UIStackView.Distribution | How subviews are sized along the axis (e.g., .fill, .equalSpacing). |
alignment | UIStackView.Alignment | How subviews are aligned perpendicular to the axis (e.g., .center, .fill). |
isBaselineRelativeArrangement | Bool | If true, aligns subviews based on their baseline (useful for text-based views). |
isLayoutMarginsRelativeArrangement | Bool | If true, uses layout margins for spacing from the stack view’s edges. |
Distribution Options
.fill: Stretches subviews to fill the stack view, respecting their intrinsic content sizes..fillEqually: Makes all subviews the same size to fill the stack view..fillProportionally: Stretches subviews proportionally based on their intrinsic content sizes..equalSpacing: Distributes subviews with equal spacing, without resizing them..equalCentering: Centers subviews with equal spacing between their centers.
Alignment Options
.fill: Stretches subviews to fill the stack view perpendicular to the axis..leading/.trailing: Aligns subviews to the leading or trailing edge (horizontal stacks)..top/.bottom: Aligns subviews to the top or bottom (vertical stacks)..center: Centers subviews perpendicular to the axis..firstBaseline/.lastBaseline: Aligns subviews based on their first or last baseline (for text-based views).
Example: Configuring Properties:
stackView.axis = .horizontal
stackView.spacing = 8
stackView.distribution = .fillEqually
stackView.alignment = .center
stackView.isLayoutMarginsRelativeArrangement = true
stackView.layoutMargins = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)Key Methods of UIStackView
UIStackView provides methods to manage its arranged subviews:
| Method | Description |
|---|---|
addArrangedSubview(_:) | Adds a view to the stack’s arranged subviews. |
removeArrangedSubview(_:) | Removes a view from the stack’s arranged subviews (but not from the view hierarchy). |
insertArrangedSubview(_:at:) | Inserts a view at a specific index in the arranged subviews. |
arrangedSubviews | Returns the array of arranged subviews. |
Example: Adding and Removing Subviews:
let button = UIButton(type: .system)
button.setTitle("Button", for: .normal)
stackView.addArrangedSubview(button)
stackView.removeArrangedSubview(button)
button.removeFromSuperview() // Required to fully remove from view hierarchyCustomizing UIStackView
Adding Subviews
Use addArrangedSubview(_:) to add views to the stack. The stack view automatically manages their Auto Layout constraints.
Example:
let label = UILabel()
label.text = "Label"
stackView.addArrangedSubview(label)
let button = UIButton(type: .system)
button.setTitle("Click Me", for: .normal)
stackView.addArrangedSubview(button)Dynamic Layouts
UIStackView excels at handling dynamic content. You can add or remove subviews, and the stack view will adjust its layout automatically.
Example: Toggling a Subview:
var isHidden = false
let toggleView = UIView()
toggleView.backgroundColor = .systemBlue
@objc func toggleSubview() {
isHidden.toggle()
if isHidden {
stackView.removeArrangedSubview(toggleView)
toggleView.removeFromSuperview()
} else {
stackView.addArrangedSubview(toggleView)
}
}Nested Stack Views
You can nest UIStackView instances to create complex layouts, such as a grid-like structure.
Example: Nested Stack View:
let outerStack = UIStackView()
outerStack.axis = .vertical
outerStack.spacing = 10
let row1Stack = UIStackView()
row1Stack.axis = .horizontal
row1Stack.spacing = 5
row1Stack.addArrangedSubview(UILabel())
row1Stack.addArrangedSubview(UIButton(type: .system))
outerStack.addArrangedSubview(row1Stack)
view.addSubview(outerStack)Best Practices
Use Auto Layout: Ensure subviews have
translatesAutoresizingMaskIntoConstraints = falseif adding constraints manually, thoughUIStackViewtypically handles this.Support Accessibility: Set
accessibilityLabelandaccessibilityTraitsfor subviews and the stack view if needed.swiftstackView.accessibilityLabel = "Control stack" stackView.accessibilityTraits = .noneOptimize for Dynamic Content: Use
UIStackViewfor layouts that may change, such as forms or dynamic lists.Combine with SnapKit: Use SnapKit for positioning the stack view itself within the view hierarchy.
Test Layouts: Verify behavior with different screen sizes, orientations, and dynamic content changes.
Avoid Over-Nesting: Limit nested stack views to maintain performance and readability.
Troubleshooting
- Subviews Not Appearing: Ensure subviews are added with
addArrangedSubview(_:)and not justaddSubview(_:). - Incorrect Spacing: Verify
spacingandlayoutMarginssettings, and checkisLayoutMarginsRelativeArrangement. - Layout Issues: Ensure subviews have appropriate intrinsic content sizes or explicit constraints if needed.
- Performance Issues: Minimize nested stack views in performance-critical areas, such as table view cells.
Example: Complete UIStackView Setup
import UIKit
import SnapKit
class ViewController: UIViewController {
let stackView = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
// Configure stack view
stackView.axis = .vertical
stackView.spacing = 10
stackView.alignment = .center
stackView.distribution = .equalSpacing
stackView.isLayoutMarginsRelativeArrangement = true
stackView.layoutMargins = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
// Add subviews
let label = UILabel()
label.text = "Welcome"
label.textAlignment = .center
let button = UIButton(type: .system)
button.setTitle("Tap Me", for: .normal)
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
stackView.addArrangedSubview(label)
stackView.addArrangedSubview(button)
// Accessibility
stackView.accessibilityLabel = "Main controls"
view.addSubview(stackView)
// Auto Layout with SnapKit
stackView.snp.makeConstraints { make in
make.center.equalToSuperview()
make.width.equalTo(200)
}
}
@objc func buttonTapped() {
print("Button tapped!")
}
}