Search code examples
iosswiftnslayoutconstraint

Arranging buttons programmatically with constraints


I have an array of buttons that I am iterating through and adding the buttons onto the view. Each button should be adjacent to the previous button, so I'm setting the leading constraint to the previous button's trailing. But the buttons end up layered on top of each other with only the top one displayed.

for k in 0 ..< buttons.count {

    view.addSubview(buttons[k])

    if k > 0 {
        buttons[k].leadingAnchor.constraint(equalTo: buttons[k-1].trailingAnchor).isActive = true
    }
}

Edit:

I don't know if this is part of the problem, but here's how I'm creating the buttons. I set each to (0,0) because I don't know where they'll end up. I assume the constraint would reposition them as needed (first time use programmatic constraints).

let size = CGRect(x: 0, y: 0, width: buttonWidth, height: buttonHeight)
let button: UIButton = UIButton(frame: size)

Solution

  • Here a simple playground that works with a UIStackView. You can play a bit and accommodate for your goal.

    UIStackViews are very flexible components if you want avoid creating constraints manually.

    //: A UIKit based Playground for presenting user interface
    
    import UIKit
    import PlaygroundSupport
    
    class MyViewController: UIViewController {
    
        override func loadView() {
            let view = UIView()
            view.backgroundColor = .white
    
            let buttons = createButtons()
            let stackView = createStackView(with: UILayoutConstraintAxis.vertical)
    
            buttons.forEach { button in
                stackView.addArrangedSubview(button)
            }
    
            view.addSubview(stackView)
    
            stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
            stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
            self.view = view
        }
    
        func createStackView(with layout: UILayoutConstraintAxis) -> UIStackView {
            let stackView = UIStackView()
            stackView.translatesAutoresizingMaskIntoConstraints = false
            stackView.axis = layout
            stackView.distribution = .equalSpacing
            stackView.spacing = 0
            return stackView
        }
    
        func createButtons() -> [UIButton] {
            var buttons = [UIButton]()
            for x in 0..<5 {
                let button = UIButton(type: .custom)
                button.backgroundColor = .red
                button.translatesAutoresizingMaskIntoConstraints = false
                button.widthAnchor.constraint(equalToConstant: 50).isActive = true
                button.heightAnchor.constraint(equalToConstant: 100).isActive = true
                button.setTitle("Title \(x)", for: .normal)
                buttons.append(button)
            }
            return buttons
        }
    }
    // Present the view controller in the Live View window
    PlaygroundPage.current.liveView = MyViewController()