Search code examples
iosswiftautolayoutconstraintssnapkit

Set constraints in code for dynamic number of elements


In my view I am going to have dynamic number of UILabels like this:

| HEADER  |
| - label |
| - label |
| - label |
| ...     |
| BUTTON  |

I am building layout with constraints for every element in code (using Snap Kit), because of dynamic number of labels. Let's say I have an array of strings, for each string in an array I create separate label, add to superview and position it below the previous one. However I am not sure how do I correctly set constraints for these labels? I believe I need to write the for-loop, but how to instruct first label to stick to header, each next to stick to previous label and at the end the button below stick to the last label?

    header.snp.makeConstraints { (make) -> Void in
        make.top.equalTo(self.view).offset(10)
        make.leading.equalTo(self.view).offset(10)
        make.trailing.equalTo(self.view).offset(10)
    }

    for object in objects {
       let label = UILabel()
       label.text = object
       self.view.addSubview(label)

       // and here how to set correct constraints for each label?
    }

    button.snp.makeConstraints { (make) -> Void in
        make.leading.equalTo(self.view).offset(10)
        make.trailing.equalTo(self.view).offset(10)
        make.bottom.equalTo(self.view).offset(10)
    }

It is first time I write all constraints in code, so sorry if that may sound like stupid question. Thanks for help.


Solution

  • You might declare a variable before the for loop to track current top view. At the beginning it would point to header and then update it on every iteration in the loop:

    var topView = header
    for object in objects {
        let label = UILabel()
        label.text = object
        self.view.addSubview(label)
    
        // and here are your constraints
        label.top.equalTo(topView).offset(10)
        label.left.equalTo(self.view).offset(20)
    
        // topView is now the current label
        topView = label
    }
    
    button.snp.makeConstraints { (make) -> Void in
        make.leading.equalTo(self.view).offset(10)
        make.trailing.equalTo(self.view).offset(10)
        make.top.equalTo(topView).offset(10)
        make.bottom.equalTo(self.view).offset(10)
    }
    

    If your labels have identical spacing then more preferred way is to try UIStackView. You declare a stack view, specify constraints for it and then in the for loop you would add labels simply by stackView.addArrangedSubview(label)