class StackVC: UIViewController { var noHeightSVs: [UIStackView] = [] var withHeightSVs: [UIStackView] = [] let bottomText: String = "Another label with different content" var topTexts: [String] = [ "This is a long label with dynamic content", "Here is even more text being changed after the initial display to show how it automatically resizes", ] override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground let labelColors: [UIColor] = [.cyan, .green,] let topText: String = topTexts.removeFirst() topTexts.append(topText) var sv: UIStackView! for _ in 0..<5 { sv = UIStackView() sv.axis = .vertical sv.spacing = 10 sv.widthAnchor.constraint(equalToConstant: 200.0).isActive = true sv.heightAnchor.constraint(equalToConstant: 300.0).isActive = true for (str, clr) in zip([topText, bottomText], labelColors) { let label = UILabel() label.numberOfLines = 0 label.backgroundColor = clr label.text = str sv.addArrangedSubview(label) } withHeightSVs.append(sv) sv = UIStackView() sv.axis = .vertical sv.spacing = 10 sv.widthAnchor.constraint(equalToConstant: 200.0).isActive = true // NO height anchor for (str, clr) in zip([topText, bottomText], labelColors) { let label = UILabel() label.numberOfLines = 0 label.backgroundColor = clr label.text = str sv.addArrangedSubview(label) } noHeightSVs.append(sv) } let g = view.safeAreaLayoutGuide let instruction = UILabel() instruction.font = .italicSystemFont(ofSize: 20.0) instruction.text = "Tap anywhere to toggle top label text." instruction.translatesAutoresizingMaskIntoConstraints = false view.addSubview(instruction) NSLayoutConstraint.activate([ instruction.topAnchor.constraint(equalTo: g.topAnchor, constant: 100.0), instruction.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 60.0), ]) let titleLabelW = UILabel() titleLabelW.text = "Stack Views WITH height constraints:" titleLabelW.textColor = .blue let titleLabelN = UILabel() titleLabelN.text = "Stack Views WITHOUT height constraints:" titleLabelN.textColor = .blue [titleLabelW, titleLabelN].forEach { v in v.translatesAutoresizingMaskIntoConstraints = false view.addSubview(v) } titleLabelW.topAnchor.constraint(equalTo: instruction.bottomAnchor, constant: 40.0).isActive = true titleLabelW.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 60.0).isActive = true var prevView: UIStackView! prevView = nil withHeightSVs.forEach { v in v.backgroundColor = .yellow v.translatesAutoresizingMaskIntoConstraints = false view.addSubview(v) v.topAnchor.constraint(equalTo: titleLabelW.bottomAnchor, constant: 40.0).isActive = true if prevView == nil { v.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 60.0).isActive = true } else { v.leadingAnchor.constraint(equalTo: prevView.trailingAnchor, constant: 20.0).isActive = true } prevView = v } titleLabelN.topAnchor.constraint(equalTo: withHeightSVs[0].bottomAnchor, constant: 60.0).isActive = true titleLabelN.leadingAnchor.constraint(equalTo: titleLabelW.leadingAnchor, constant: 0.0).isActive = true prevView = nil noHeightSVs.forEach { v in v.backgroundColor = .yellow v.translatesAutoresizingMaskIntoConstraints = false view.addSubview(v) v.topAnchor.constraint(equalTo: titleLabelN.bottomAnchor, constant: 40.0).isActive = true if prevView == nil { v.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 60.0).isActive = true } else { v.leadingAnchor.constraint(equalTo: prevView.trailingAnchor, constant: 20.0).isActive = true } prevView = v } let dists: [UIStackView.Distribution] = [ .fill, .equalSpacing, .equalCentering, .fillEqually, .fillProportionally, ] for (sv, d) in zip(withHeightSVs, dists) { sv.distribution = d } for (sv, d) in zip(noHeightSVs, dists) { sv.distribution = d } let infos: [String] = [ ".fill", ".equalSpacing", ".equalCentering", ".fillEqually", ".fillProportionally", ] for (str, sv) in zip(infos, withHeightSVs) { let label = UILabel() label.font = .systemFont(ofSize: 16, weight: .bold) label.textColor = .red label.textAlignment = .center label.text = str label.translatesAutoresizingMaskIntoConstraints = false view.addSubview(label) NSLayoutConstraint.activate([ label.leadingAnchor.constraint(equalTo: sv.leadingAnchor), label.trailingAnchor.constraint(equalTo: sv.trailingAnchor), label.bottomAnchor.constraint(equalTo: sv.topAnchor, constant: -8.0), ]) } for (str, sv) in zip(infos, noHeightSVs) { let label = UILabel() label.font = .systemFont(ofSize: 16, weight: .bold) label.textColor = .red label.textAlignment = .center label.text = str label.translatesAutoresizingMaskIntoConstraints = false view.addSubview(label) NSLayoutConstraint.activate([ label.leadingAnchor.constraint(equalTo: sv.leadingAnchor), label.trailingAnchor.constraint(equalTo: sv.trailingAnchor), label.bottomAnchor.constraint(equalTo: sv.topAnchor, constant: -8.0), ]) } } override func touchesBegan(_ touches: Set, with event: UIEvent?) { let topText: String = topTexts.removeFirst() topTexts.append(topText) withHeightSVs.forEach { sv in if let v = sv.arrangedSubviews.first as? UILabel { v.text = topText } } noHeightSVs.forEach { sv in if let v = sv.arrangedSubviews.first as? UILabel { v.text = topText } } } }