Search code examples
iosswiftuikitaxisuistackview

UIStackView overlaps in z-direction


I'm going to make a numPad using stackView this is my code

private func setKeypadButton(num: Int) -> UIButton {
    let button = UIButton()
    button.setTitle(String(num), for: .normal)
    button.titleLabel?.font = .systemFont(ofSize: 50)
    button.setTitleColor(.black, for: .normal)
    button.frame.size = CGSize(width: 60, height: 60)
    button.tapPublisher
        .sink {
            guard let num = button.titleLabel?.text else { return }
            print(num)
        }.store(in: &subscription)
    
    return button
}

private func setKeypad() {
    let keypadHorizontalStackView = UIStackView()
    keypadHorizontalStackView.axis = .horizontal
    keypadHorizontalStackView.spacing = 0
    for i in 1...9 {
        let button = setKeypadButton(num: i)
        keypadHorizontalStackView.addArrangedSubview(button)
        if i % 3 == 0 {
            keypadVerticalStackView.addArrangedSubview(keypadHorizontalStackView)
            keypadHorizontalStackView.arrangedSubviews.forEach {
                keypadHorizontalStackView.removeArrangedSubview($0)
            }
        }
    }
}

SetKeypad function is executed in viewDidLoad I expect the view to come out like this

123
456
789

But my buttons overlap in the z-direction

view

What am I missing?


Solution

  • First this method .removeArrangedSubview doesn't remove provided view from stack's subview array, therefore the view is still display as a part of view hierarchy, that why you see your button overlap in z-direction. You should use view.removeFromSuperview if you want to remove view from superview. You can read about removeArrangedSubview here

    Second stackView is a class, so it's reference type. So this line keypadVerticalStackView.addArrangedSubview(keypadHorizontalStackView) just add the same horizontal stack view to your vertical stack view and its not correct solution.

    If I want to make UI display as your expectation, i will do something like

    let horizontalStackViews = [UIStackView(), UIStackView(), UIStackView()]
        horizontalStackViews.forEach { (stackView) in
            stackView.axis = .horizontal
            stackView.spacing = 0
            stackView.distribution = .equalSpacing
            verticalStackView.addArrangedSubview(stackView)
        }
        var row = 0
        var number = 1
        repeat {
            horizontalStackViews[row].addArrangedSubview(setKeypadButton(num: number))
            number += 1
            if number % 3 == 1 { row += 1 }
        } while row < 3