iosswiftuibuttonuistackviewcgsize

UIStackView does not respect size of programmatically added buttons


I have a UIStackView that includes either three or four custom UIButtons. All buttons are completely rounded, the left and right buttons are slightly bigger than the center one/two. Somehow, I can't get UIStackView to respect the bounds set by DeckPageButton.

Here's the function in my VC that renders the buttons:

    private func setupButtons() {
        guard let deck = self.deck else {
            log.error("Failed to load deck")
            return
        }
        
        let nFloat = CGFloat(deck.type.buttons.count)
        let rad = (deckButtonsStackView.bounds.size.width - (8.0 * (nFloat - 1.0))) / nFloat
        for type in deck.type.buttons {
            let button = DeckPageButton()
            button.setupView(type: type, size: CGSize(width: rad, height: rad))
            button.translatesAutoresizingMaskIntoConstraints = false
            deckButtonsStackView.addArrangedSubview(button)
        }
    }

And here's the setupView function:

func setupView(type: DeckPageButtonType, size: CGSize) {
        bounds.size = size.resized(multiplier: type.radiusCoefficient)
        layer.cornerRadius = size.height / 2
        layer.borderWidth = 5
        layer.borderColor = type.borderColor
    }

I tried different Alignment and Distribution options for the deckButtonsStackView and none of them respect the

  1. aspect ratio of the Buttons - they are not square, hence also not circular
  2. edge size - all buttons are the same size even though the inner ones set their boundsto a smaller scale

Here's the best outcome, which I've had with FillEqually (same code for three and four button options):

StackView with three rounded buttons

StackView with four rounded buttons

I've also tried setting the frame of the buttons instead of bounds and keeping everything else the same, this was the outcome:

StackView with three rounded buttons

StackView with four rounded buttons

Is UIStackView just a bad choice for my goal? If so, what would be a better approach?


Solution

  • You should use constraints to set the size of each button:

    In setUpView, instead of bounds.size = ...

    let size = size.resized(multiplier: type.radiusCoefficient)
    NSLayoutConstraint.activate([
        widthAnchor.constraint(equalToConstant: size.width),
        heightAnchor.constraint(equalToConstant: size.height)
    ])
    

    After that, setting the spacing to some reasonable value, alignment to "Center", and distribution to "Equal Centering" should give you a desired result.