Skip to content

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:

swift
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:

PropertyTypeDescription
arrangedSubviews[UIView]The array of views managed by the stack view (read-only).
axisUILayoutConstraintAxisThe orientation of the stack: .horizontal or .vertical.
spacingCGFloatThe spacing between arranged subviews.
distributionUIStackView.DistributionHow subviews are sized along the axis (e.g., .fill, .equalSpacing).
alignmentUIStackView.AlignmentHow subviews are aligned perpendicular to the axis (e.g., .center, .fill).
isBaselineRelativeArrangementBoolIf true, aligns subviews based on their baseline (useful for text-based views).
isLayoutMarginsRelativeArrangementBoolIf 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:

swift
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:

MethodDescription
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.
arrangedSubviewsReturns the array of arranged subviews.

Example: Adding and Removing Subviews:

swift
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:

swift
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:

swift
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:

swift
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, though UIStackView typically handles this.

  • Support Accessibility: Set accessibilityLabel and accessibilityTraits for subviews and the stack view if needed.

    swift
    stackView.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 just addSubview(_:).
  • Incorrect Spacing: Verify spacing and layoutMargins settings, and check isLayoutMarginsRelativeArrangement.
  • 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

swift
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!")
    }
}

Resources

Released under the MIT License.