I have a UIStackView that contains multiple arranged subviews. I want to dynamically hide certain views within the stack view when auto layout attempts to reduce the stack view's size. I'm looking for a way to achieve this behavior using auto layout and without manually manipulating the frame.
I've tried setting the isHidden property of the subviews, but it doesn't seem to update the layout of the stack view correctly. The views still take up space within the stack view.
What would be the recommended approach to hide views in a stack view when auto layout attempts to reduce its size? Are there any specific methods or techniques that should be used to achieve this behavior?
Any guidance or code examples would be greatly appreciated. Thank you!
I've try to override layoutSubviews method.
    override func layoutSubviews() {
        super.layoutSubviews()

        for view in stackView.arrangedSubviews {
            if visibilityManager.shouldBeVisible(view: view) {
                if let view = view as? MyButton {
                    if view.intrinsicContentSize.height > view.bounds.height {
                        view.isHidden = true
                    } else {
                        view.isHidden = false
                    }
                }
            }
        }
    }

Expect:
The views in the stack view will be hidden
Actual:
Views are just compressed

Hide views in a stack view when auto layout attempts to reduce the stack view size?
When we set .isHidden = true on a stack view's arranged subview, that subview remains in the .arrangedSubviews collection but it is removed from the hierarchy and no longer has a valid frame.
Another approach would be to set the .alpha to either 1.0 or 0.0 to "show / hide" the view.
We create a custom view subclass - let's call it AutoHideSubviewsView. It will have a stack view with Top / Leading / Trailing constraints, but no Bottom constraint.
When the view frame changes - gets shorter or taller - we loop through the arranged subviews and:

get the frame
convert it to the view coordinate space (it's relative to the stack view itself)
if the view's bounds contains the frame, set its .alpha = 1.0 (show it)
else, set its .alpha = 0.0 (hide it)

Here's some quick example code...
Custom View
class AutoHideSubviewsView: UIView {
    
    let stackView: UIStackView = {
        let v = UIStackView()
        v.axis = .vertical
        v.spacing = 12.0
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    private func commonInit() {
        addSubview(stackView)
        NSLayoutConstraint.activate([
            stackView.topAnchor.constraint(equalTo: topAnchor, constant: 8.0),
            stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8.0),
            stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8.0),
            // NO Bottom constraint
        ])
        // not strictly necessary, but let's do this anyway
        self.clipsToBounds = true
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        // on first layout, the stackView's subview's frames are not set
        //  so force another layout pass
        if stackView.arrangedSubviews.first!.frame.height == 0.0 {
            stackView.setNeedsLayout()
            stackView.layoutIfNeeded()
            self.setNeedsLayout()
            self.layoutIfNeeded()
            return
        }
        for v in stackView.arrangedSubviews {
            // the frames of the arranged subviews are
            //  relative to the stack view frame, so
            //  we want to convert the frames in case
            //  the stack view TOP is not Zero
            let r = stackView.convert(v.frame, to: self)
            // animate the alpha change so we can see it
            UIView.animate(withDuration: 0.3, animations: {
                v.alpha = self.bounds.contains(r) ? 1.0 : 0.0
            })
        }
    }
    
}

Example Controller
class ViewController: UIViewController {
    
    let ahView = AutoHideSubviewsView()
    
    var hConstraint: NSLayoutConstraint!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        
        // grow and shrink buttons
        var cfg = UIButton.Configuration.gray()
        cfg.title = "Shrink"
        let btn1 = UIButton(configuration: cfg, primaryAction: UIAction() { _ in
            if self.hConstraint.constant > 15.0 {
                self.hConstraint.constant -= 10.0
            }
        })
        cfg.title = "Grow"
        let btn2 = UIButton(configuration: cfg, primaryAction: UIAction() { _ in
            self.hConstraint.constant += 10.0
        })

        [ahView, btn1, btn2].forEach { v in
            v.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(v)
        }

        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            
            ahView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            ahView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            ahView.widthAnchor.constraint(equalToConstant: 200.0),
            
            btn1.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
            btn1.leadingAnchor.constraint(equalTo: ahView.trailingAnchor, constant: 20.0),
            btn1.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            
            btn2.topAnchor.constraint(equalTo: btn1.bottomAnchor, constant: 20.0),
            btn2.leadingAnchor.constraint(equalTo: ahView.trailingAnchor, constant: 20.0),
            btn2.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            
        ])
        
        // start with the view height at 320
        hConstraint = ahView.heightAnchor.constraint(equalToConstant: 320.0)
        hConstraint.isActive = true
        
        // let's add 3 labels and 3 buttons to the custom view's stackView
        let strings: [String] = ["First", "Second", "Third"]
        let colors: [UIColor] = [.cyan, .green, .yellow]
        for (str, c) in zip(strings, colors) {
            let label = UILabel()
            label.font = .systemFont(ofSize: 24, weight: .light)
            label.text = str
            label.textAlignment = .center
            label.backgroundColor = c
            label.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
            var cfg = UIButton.Configuration.filled()
            cfg.title = str
            let btn = UIButton(configuration: cfg, primaryAction: UIAction() { _ in
                print("\(str) Button Tapped")
            })
            ahView.stackView.addArrangedSubview(label)
            ahView.stackView.addArrangedSubview(btn)
        }

        // so we can see the framing
        ahView.backgroundColor = .red
    }
    
}

Looks like this (custom view's background is red):

Tapping the "Shrink" button will decrease the height of the view, tapping the "Grow" button will increase it.



To make it really easy to see what's happening, I animate the .alpha change so the subviews "fade" in and out.
Here's an animation (too big to post here): https://imgur.com/a/glRRh2O
