What does a UIStackView own, and what is the difference between hiding, removing from arranged subviews and removing from the superview?
Predict first
What do hiding and the two removals do to a stack view?
import UIKit
let s = UIStackView()
s.axis = .vertical
s.spacing = 10
let a = UIView(), b = UIView(), c = UIView()
for v in [a, b, c] {
v.translatesAutoresizingMaskIntoConstraints = false
v.heightAnchor.constraint(equalToConstant: 20).isActive = true
s.addArrangedSubview(v)
}
s.frame = CGRect(x: 0, y: 0, width: 100, height: 500)
func h() -> CGFloat { s.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height }
print(s.arrangedSubviews.count, s.subviews.count, h())
b.isHidden = true
print("hidden:", s.arrangedSubviews.count, h())
s.removeArrangedSubview(c)
print("removeArranged:", s.arrangedSubviews.count, s.subviews.count, c.superview === s)
c.removeFromSuperview()
print("removeFromSuperview:", s.arrangedSubviews.count, s.subviews.count)
- 3 3 80.0 / hidden: 3 50.0 / removeArranged: 2 3 true / removeFromSuperview: 2 2
- 3 3 80.0 / hidden: 2 50.0 / removeArranged: 2 2 false / removeFromSuperview: 2 2
- 3 3 60.0 / hidden: 3 40.0 / removeArranged: 2 3 true / removeFromSuperview: 2 2
Mental model. A stack view is a shelf manager: hiding a book leaves its slot closed up, taking it off the managed list leaves the book lying on the shelf, and only throwing it out removes it.
A stack view is a layout container that generates constraints for its arrangedSubviews; it does not draw anything itself. Arranged views are always also subviews. Three operations look alike and differ: setting isHidden = true keeps the view arranged but collapses its space and one spacing gap (in the check, three 20-point views with 10 spacing measure 80, and with the middle one hidden they measure 50); removeArrangedSubview(_:) only stops the stack from managing it, so the view stays in the hierarchy (the check shows superview === s still true, subview count unchanged) and keeps whatever frame it last had; removeFromSuperview() removes it from both lists.
So to delete a row you call removeFromSuperview, to temporarily hide it you set isHidden (animatable inside an animation block, which is why stack views are the easy way to build expanding sections), and removeArrangedSubview is correct only when you want to keep managing that view's frame yourself. Related details: setCustomSpacing(_:after:) overrides the gap after one view, arranged subviews need no constraints for their position, but they do need a way to get a size on the stack's cross axis (intrinsic size or constraints), and a plain addSubview does not arrange anything. Nested stacks multiply the Auto Layout cost, so prefer a flat layout or a collection view for long, scrolling content (Q277).
Hidden stays arranged but collapses; removeArrangedSubview leaves it a subview; removeFromSuperview drops both.
Common traps
- Calling
removeArrangedSubviewand expecting the view to disappear. It is still on screen, unmanaged. - Using many nested stacks for a long list. Every view adds constraints; use a collection or table view.
They might follow up with
- How do I animate collapsing a row? Set
isHiddeninsideUIView.animate; the stack view animates the layout. - Does a hidden arranged view still exist? Yes, it is still in
arrangedSubviews.
Related questions
- 9.1.1 How does Auto Layout work, and what are intrinsic size, content hugging, compression resistance, priorities…
- 9.1.2 What is the difference between layoutSubviews and draw(_:), and what triggers each?
← Which initialisers run when a view or view controller is created in… How does UIScrollView scroll, how do you convert points between views… →