Search code examples
swiftxcodeautolayoutuistackview

How can a stackview dynamically change the spacing between the elements nested inside of it


For months now I have been trying to wrap my head around stackviews and how they work. For that reason I have created a project which has 4 buttons nested inside of a stack view with constant width and height. Now depending on the iPhone screen size, I want the buttons inside of the stackview to maintain their width and size, but the spacing between them to get smaller or bigger. This is done perfectly if I manually adjust the stackview size using my mouse. But, the moment I add top and bottom constraints which should have the same effect, the buttons inside of the stack view shrinks or weirdly stretched even if they all have constant height with the priority set to 1000.

You can try it for yourself by creating a stack view with some buttons inside of it and then set their width and height constant. Afterwards add top and bottom constraints and preview it on a smaller screen size than the one you are creating it.

Preview on an iPhone XS and if the screen is smaller the gap between the buttons should dynamically change to being bigger or smaller:

enter image description here

Preview on an iPhone 8:

enter image description here

And how it should look like:

enter image description here

Can anyone explain to me why this is happening and how I can achieve the result I want?


Solution

  • Instead of adding a bottom constraint you should only add height constraint to UIStackView, checkout following example

    let buttons = [UIButton(), UIButton(), UIButton(), UIButton()]
    for (index, button) in buttons.enumerated() {
        button.backgroundColor = .red
        button.setTitle("Category Button \(index)", for: .normal)
        button.setTitleColor(.black, for: .normal)
    }
    let stackView = UIStackView(arrangedSubviews: buttons)
    stackView.axis = .vertical
    stackView.distribution = .equalSpacing
    stackView.translatesAutoresizingMaskIntoConstraints = false
    self.view.addSubview(stackView)
    
    let salGuide = self.view.safeAreaLayoutGuide
    NSLayoutConstraint.activate([
        stackView.topAnchor.constraint(equalTo: salGuide.topAnchor, constant: 16.0),
        stackView.centerXAnchor.constraint(equalTo: salGuide.centerXAnchor, constant: 0),
        stackView.widthAnchor.constraint(equalTo: salGuide.widthAnchor, multiplier: 0.6),
        stackView.heightAnchor.constraint(equalTo: salGuide.heightAnchor, multiplier: 0.6)
    ])
    

    Note that multiplier: 0.6 gives 60% of available width and height to UIStackView, to use constant width/height just change parameter name from multiplier to constant and provide appropriate parameter value.

    iPhone SE

    enter image description here

    iPhone Xs Max

    enter image description here