multilevel uistackviews autolayout not working

I'm trying to build a layout using this idea:

scroll -> UIStackView (vertical) -> UIStackView (horizontal) -> UIStackView (vertical) [ view + n(UIStackView (horizontal)-> UIStackView (vertical) -> view + n UIStackView ....)]

It works until the second level but after that, all the views are displayed with frame 0.

Am I doing something wrong?

Examples of implementation:

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        let scroll = UIScrollView()
        scroll.backgroundColor = .blue
        view.addSubview(scroll)
        scroll.translatesAutoresizingMaskIntoConstraints = false
        scroll.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        scroll.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        scroll.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        scroll.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true

        
        let stackV = UIStackView()
        stackV.axis = .vertical
        stackV.backgroundColor = .red
        stackV.translatesAutoresizingMaskIntoConstraints = false
        scroll.addSubview(stackV)
        
        stackV.topAnchor.constraint(equalTo: scroll.topAnchor).isActive = true
        stackV.bottomAnchor.constraint(equalTo: scroll.bottomAnchor).isActive = true
        stackV.leadingAnchor.constraint(equalTo: scroll.leadingAnchor).isActive = true
        stackV.trailingAnchor.constraint(equalTo: scroll.trailingAnchor).isActive = true
        stackV.addArrangedSubview(UIView())

        var stackH: UIStackView
        for j in (0...3) {
            stackH = UIStackView()
            stackH.axis = .horizontal
            stackH.backgroundColor = .green
            stackH.translatesAutoresizingMaskIntoConstraints = false
            
            stackV.addArrangedSubview(stackH)
            
            stackH.leadingAnchor.constraint(equalTo: stackV.leadingAnchor).isActive = true
            stackH.trailingAnchor.constraint(equalTo: stackV.trailingAnchor).isActive = true

            var label: UILabel
            var stackCol: UIStackView
            for i in (0...3) {
                stackCol = UIStackView()
                stackCol.axis = .vertical
                stackCol.backgroundColor = .cyan
                stackCol.spacing = 4
                stackCol.translatesAutoresizingMaskIntoConstraints = false
                stackH.addArrangedSubview(stackCol)
                stackH.addArrangedSubview(UIView())


                stackCol.leadingAnchor.constraint(equalTo: stackH.leadingAnchor).isActive = true
                stackCol.trailingAnchor.constraint(equalTo: stackH.trailingAnchor).isActive = true

                label = UILabel()
                label.translatesAutoresizingMaskIntoConstraints = false
                
                label.text = "teste cacetas"
                label.backgroundColor = .orange
                
                label.heightAnchor.constraint(equalToConstant: 30).isActive = true
                label.widthAnchor.constraint(equalToConstant: 30).isActive = true

                stackCol.addArrangedSubview(label)
                stackCol.addArrangedSubview(UIView())
                label.leadingAnchor.constraint(equalTo: stackCol.leadingAnchor).isActive = true
                label.trailingAnchor.constraint(equalTo: stackCol.trailingAnchor).isActive = true
                stackCol.layoutIfNeeded()
                
            }
        }
        
    }
}

I tried lots of different constraint configurations but it not work.

Upvotes: 0

Views: 48

Answers (1)

Immanuel
Immanuel

Reputation: 1166

The main reason for frame becomes zero is because of these two constraints

stackCol.leadingAnchor.constraint(equalTo: stackH.leadingAnchor).isActive = true
stackCol.trailingAnchor.constraint(equalTo: stackH.trailingAnchor).isActive = true

After removing those two extra constraints the view displayed. And below extra code is also not needed

stackV.addArrangedSubview(UIView())
stackH.leadingAnchor.constraint(equalTo: stackV.leadingAnchor).isActive = true
stackH.trailingAnchor.constraint(equalTo: stackV.trailingAnchor).isActive = true
stackH.addArrangedSubview(UIView())
stackCol.addArrangedSubview(UIView())
label.leadingAnchor.constraint(equalTo: stackCol.leadingAnchor).isActive = true
label.trailingAnchor.constraint(equalTo: stackCol.trailingAnchor).isActive = true
stackCol.layoutIfNeeded()

I have updated the code and added spacing

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let scroll = UIScrollView()
        scroll.backgroundColor = .blue
        view.addSubview(scroll)
        scroll.translatesAutoresizingMaskIntoConstraints = false
        scroll.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        scroll.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
        scroll.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
        scroll.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
        
        let stackV = UIStackView()
        stackV.axis = .vertical
        stackV.spacing = 20
        stackV.backgroundColor = .red
        stackV.translatesAutoresizingMaskIntoConstraints = false
        scroll.addSubview(stackV)
        
        stackV.topAnchor.constraint(equalTo: scroll.contentLayoutGuide.topAnchor).isActive = true
        stackV.bottomAnchor.constraint(equalTo: scroll.contentLayoutGuide.bottomAnchor).isActive = true
        stackV.leadingAnchor.constraint(equalTo: scroll.contentLayoutGuide.leadingAnchor).isActive = true
        stackV.trailingAnchor.constraint(equalTo: scroll.contentLayoutGuide.trailingAnchor).isActive = true
        
        var stackH: UIStackView
        for _ in (0...3) {
            stackH = UIStackView()
            stackH.axis = .horizontal
            stackH.spacing = 20
            stackH.backgroundColor = .green
            stackH.translatesAutoresizingMaskIntoConstraints = false
            stackV.addArrangedSubview(stackH)
            
            for _ in (0...3) {
                let stackCol = UIStackView()
                stackCol.axis = .vertical
                stackCol.backgroundColor = .cyan
                stackCol.spacing = 20
                stackCol.translatesAutoresizingMaskIntoConstraints = false
                stackH.addArrangedSubview(stackCol)
                
                for _ in 0...3 {
                    let label = UILabel()
                    label.translatesAutoresizingMaskIntoConstraints = false
                    
                    label.text = "teste cacetas"
                    label.backgroundColor = .orange
                    
                    label.heightAnchor.constraint(equalToConstant: 100).isActive = true
                    label.widthAnchor.constraint(equalToConstant: 200).isActive = true
                    
                    stackCol.addArrangedSubview(label)
                }

            }
        }
        
    }
    
}

Upvotes: 0

Related Questions