2

I'm trying to autolayout my stack views and create its arrangedSubView(2 labels and 1 image) in code, but only one set of stack view is appear in simulator. When print the results in console, all labels and image have values, except all stack view's frame is 0.0;0.0. Why does happen like this? Why the stack view do not appear? Please see my code below:

code

let contentView: UIView = UIView()
let stackView: UIStackView = UIStackView()

var singleStack = Array(count: 6, repeatedValue: UIStackView())
var timeLabel = Array(count: 6, repeatedValue: UILabel())
var iconImage = Array(count: 6, repeatedValue: UIImageView())
var tempLabel = Array(count: 6, repeatedValue: UILabel())

override func viewDidLoad() {
    super.viewDidLoad()

    for index in 0...5 {            
        timeLabel[index].text = "0\(index):00"
        iconImage[index].image = UIImage(named: "sunny")!
        tempLabel[index].text = "0\(index)°"

        singleStack[index].addArrangedSubview(timeLabel[index])
        singleStack[index].addArrangedSubview(iconImage[index])
        singleStack[index].addArrangedSubview(tempLabel[index])

        singleStack[index].translatesAutoresizingMaskIntoConstraints = false
        singleStack[index].axis = .Vertical
        singleStack[index].alignment = .Center
        singleStack[index].distribution = .FillEqually

        stackView.addArrangedSubview(singleStack[index])

        print("\(timeLabel[index].text!)")
        print("\(iconImage[index].image!)")
        print("\(tempLabel[index].text!)")
        print("\(singleStack[index])")
        print("\(stackView)")
        }

    stackView.translatesAutoresizingMaskIntoConstraints = false
    stackView.axis = .Horizontal
    stackView.alignment = .Fill
    stackView.distribution = .FillEqually

    contentView.backgroundColor = UIColor.lightGrayColor()

    view.addSubview(contentView)
    contentView.addSubview(stackView)

    contentView.translatesAutoresizingMaskIntoConstraints = false

    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
        "H:|[stackView]|",
        options: [],
        metrics: nil,
        views: ["stackView": stackView]))

    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
        "V:|[stackView]|",
        options: [],
        metrics: nil,
        views: ["stackView": stackView]))
    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
        "H:|-[contentView]-|",
        options: [],
        metrics: nil,
        views: ["contentView": contentView]))

    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
        "V:[contentView(120)]-16-|",
        options: [],
        metrics: nil,
        views: ["contentView": contentView]))

}

The printed results in console (just use one piece for example)

01:00
<UIImage: 0x7fb61944f630>, {32, 32}
01°
<UIStackView: 0x7fb6194462c0; frame = (0 0; 0 0); layer = <CATransformLayer: 0x7fb619445e70>>
<UIStackView: 0x7fb619443b50; frame = (0 0; 0 0); layer = <CATransformLayer: 0x7fb6194433b0>>

As you can see, all labels and image have values, but all stack view's frame is 0.0;0.0.

Hope anyone can solve my problem, thank you very much in advance!

stephen
  • 519
  • 6
  • 22
  • What line of code are you expecting will change "stackViews" frame? Right now it just seems like you are just initializing both stack views with '= UIStackView()' which by default will give a frame of 0.0, 0.0, which is what you are getting returned. – Benjamin Lowry Aug 29 '16 at 00:39
  • @BenjaminLowry He's using constraints. – matt Aug 29 '16 at 02:10
  • @matt correct me if I'm wrong, but isn't he printing the value of the stack views before the constraints are created? – Benjamin Lowry Aug 29 '16 at 02:41
  • @BenjaminLowry You're not at all wrong! But then you should point that out. Your comment makes it sound like there's something wrong with how he's creating the stack views, and there isn't since his constraints will (later) give them an actual frame. If you mean that the problem is with when he's measuring, that's an excellent point (and in fact would make a good answer). – matt Aug 29 '16 at 03:01

1 Answers1

1

When you initialize an array with Array(count: , repeatedValue: ) and the repeatedValue is a class you are going to get an array of pointers pointing to the same instance of the class count times over. Classes in swift are passed by reference. So singleStack[0] === singleStack[2] which === singleStack[5] etc. This is why only one stack view shows up. You should change your for loop to something like:

for index in 0...5 {
    let singleStack = UIStackView()
    let timeLabel = UILabel()
    let iconImage = UIImageView()
    let tempLabel = UILabel()

    timeLabel.text = "0\(index):00"

    iconImage.image = UIImage(named: "sunny")!

    tempLabel.text = "0\(index)°"

    singleStack.addArrangedSubview(timeLabel)
    singleStack.addArrangedSubview(iconImage)
    singleStack.addArrangedSubview(tempLabel)

    singleStack.axis = .Vertical
    singleStack.alignment = .Center
    singleStack.distribution = .FillEqually
    self.stackView.addArrangedSubview(singleStack)
}

Unless you absolutely need an array of the views you are adding to your stack views and using arrangedSubviews would be clunky. In which case it would be better to have use an initialization block like:

let singleStack: [UIStackView] =
{
    var singleStacks = [UIStackView]()
    for _ in 0...5
    {
        singleStacks.append(UIStackView())
    }
    return singleStacks
}()

etc…

beyowulf
  • 15,101
  • 2
  • 34
  • 40