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 hierarchy
Customizing 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 = false
if adding constraints manually, thoughUIStackView
typically handles this.Support Accessibility: Set
accessibilityLabel
andaccessibilityTraits
for subviews and the stack view if needed.swiftstackView.accessibilityLabel = "Control stack" stackView.accessibilityTraits = .none
Optimize for Dynamic Content: Use
UIStackView
for 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
spacing
andlayoutMargins
settings, 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!")
}
}