2

I created a stackview with labels programatically in Swift. However, I was trying to find out how i can update the labels programmatically? (I did not use storyboard or IBOutlets)

  let LabelStack: UIStackView = {
      
        let label1: UILabel = {
            let label = UILabel()
            label.text = "Label 1"
            label.font = .systemFont(ofSize: 14, weight: .bold)
            label.numberOfLines = 0
            label.backgroundColor = .clear
            label.textAlignment = .left
            label.sizeToFit()
            return label
        }()
        
        let label2: UILabel = {
            let label = UILabel()
            label.text = "Label 2"
            label.font = .systemFont(ofSize: 14, weight: .bold)
            label.numberOfLines = 0
            label.backgroundColor = .clear
            label.textAlignment = .left
            label.sizeToFit()
            return label
        }()
        
        let stack = UIStackView(arrangedSubviews: [label1, label2])
        stack.distribution = .equalSpacing
        stack.spacing = 4.0
        return stack
    }()

When trying to update the label text with a function, I wasnt sure how to access the label properties to make this change. Normally, for a label created outside of the stack i could simply use:

func updateLabel() {
    label1.text = "Updated Label 1 text"
    label2.text = "Updated Label 2 text" 
}

What is the syntax to use to access these label properties sitting inside the UIStackview with labels?

Daniel C
  • 113
  • 1
  • 8
  • 1
    Make `label1` and `label2` outside `LabelStack`, put them as the same level of `LabelStack`. And I'd rename `LabelStack` with `labelStack` (starting with a lwoercase) – Larme Nov 09 '21 at 12:03
  • Why do you want to create them inside? – Vollan Nov 09 '21 at 12:03

2 Answers2

2

You can make them outside let labelStack: UIStackView = {

    let label1: UILabel = {
        let label = UILabel()
        label.text = "Label 1"
        label.font = .systemFont(ofSize: 14, weight: .bold)
        label.numberOfLines = 0
        label.backgroundColor = .clear
        label.textAlignment = .left
        label.sizeToFit()
        return label
    }()
    
    let label2: UILabel = {
        let label = UILabel()
        label.text = "Label 2"
        label.font = .systemFont(ofSize: 14, weight: .bold)
        label.numberOfLines = 0
        label.backgroundColor = .clear
        label.textAlignment = .left
        label.sizeToFit()
        return label
    }()

let labelStack: UIStackView = { 
    let stack = UIStackView(arrangedSubviews: [label1, label2])
    stack.distribution = .equalSpacing
    stack.spacing = 4.0
    return stack
}()

Or do this

if let label1 = labelStack.arrangedSubviews.first as? UILabel {
  // proceed
}
if let label2 = labelStack.arrangedSubviews.last as? UILabel {
  // proceed
}
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • unless that is inside a function it wont work as labelStack wont be able to find label1 and 2 – Vollan Nov 09 '21 at 12:12
0

You can create them outside. But that will require you to add the arrangedSubviews later as it has not been initialized yet. So you could make the stackView Lazy, which waits for init to be run:

let label1: UILabel = {
    let label = UILabel()
    label.text = "Label 1"
    label.font = .systemFont(ofSize: 14, weight: .bold)
    label.numberOfLines = 0
    label.backgroundColor = .clear
    label.textAlignment = .left
    label.sizeToFit()
    return label
}()

let label2: UILabel = {
    let label = UILabel()
    label.text = "Label 2"
    label.font = .systemFont(ofSize: 14, weight: .bold)
    label.numberOfLines = 0
    label.backgroundColor = .clear
    label.textAlignment = .left
    label.sizeToFit()
    return label
}()


lazy var labelStack: UIStackView = {
    let stack = UIStackView(arrangedSubviews: [label1, label2])
    stack.distribution = .equalSpacing
    stack.spacing = 4
    return stack
}()

If you have to labels and 2 texts statically you can do this:

   zip(labelStack.arrangedSubviews, ["textupdate1", "textupdate2"]).forEach { (element value) in
        (element as? UILabel)?.text = value
    }
Vollan
  • 1,887
  • 11
  • 26
  • Thank you all for your help! I have followed your advice and moved the labels out of the Stack and made the stack lazy var. That worked for me at the end, even though i would have hoped to have an easier way to access the labels that were inside a stack. – Daniel C Nov 11 '21 at 10:39