Search code examples
swiftautolayoutnslayoutconstraintuistackview

Swift - How to set spacing between variable number of buttons in Horizontal StackView?


I'm using a horizontal UIStackView that can contain up to 3 UIButtons. (could be just 1, could be 2, or 3)

I want to have them centered, with the same space between each of them, like so: enter image description here

I don't seem to be able to pull this off... I've tried every combination of Distribution and Alignment, but I can’t get it right.

Here's the stackView's constraints:

fileprivate func setupStackViewConstraints() {
    stackView.translatesAutoresizingMaskIntoConstraints = false
    
    NSLayoutConstraint.activate([
        stackView.topAnchor.constraint(equalToConstant: 60),
        stackView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
        stackView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
        stackView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor)
    ])
}

And here's the buttons' constraints:

fileprivate func setupFacebookButton() {
    let facebookButton = UIButton()
    
    facebookButton.setImage(UIImage(named: "facebookSocialIcon"), for: .normal)
    facebookButton.imageView?.contentMode = .scaleAspectFit
    facebookButton.addTarget(self, action: #selector(facebookButtonWasTapped), for: .touchUpInside)
    
    // -----------------------------------
    
    facebookButton.translatesAutoresizingMaskIntoConstraints = false

    NSLayoutConstraint.activate([
        facebookButton.widthAnchor.constraint(equalToConstant: 40),
        facebookButton.heightAnchor.constraint(equalToConstant: 40)
    ])
    
    // -----------------------------------
    
    stackView.addArrangedSubview(facebookButton)
}

Any ideas?


Solution

  • The distribution and alignment are obvious here. You want "Equal Spacing" and "Center". You should also set a suitable spacing.

    The "hard bit" is how to get the arranged views to horizontally align in the middle, since the alignment property is only about alignment perpendicular to axis.

    The key is to let the stack view have a flexible width, and align it horizontally in the center. This means removing the leading and trailing constraints, and adding a center X constraint.

    Therefore, these are the constraints on your stack view:

    NSLayoutConstraint.activate([
        stackView.topAnchor.constraint(equalToConstant: 60),
        stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        stackView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor)
    ])
    

    Note that the stack view will extend its width to fit all the arranged subviews in it. This means that if you have too many arranged subviews, some of them might go offscreen. If you want them to "wrap" to the next line, consider using a UICollectionView instead :)