Roman Roman - 4 months ago 10
Swift Question

Positioning miltiple views programmatically in swift

With your last help my loop is functioning well. But only once. If I try to reload it I get the following mistake: "Index out of range" in the following line:

let cardOnTop = cards[index-8]


Could somebody help me?

Here is my code:

func layoutCards() {

// create cards array with several elements
var cards = (1...64).map { _ in UIView() }// array with several cards


//Loop through each card in the array
for index in 0...cards.count-1 {



// place the card in the view and turn off translateAutoresizingMask
let thisCard = cards[index]

thisCard.layer.borderWidth = 1
thisCard.layer.borderColor = UIColor.blackColor().CGColor
thisCard.backgroundColor = UIColor.greenColor()

thisCard.translatesAutoresizingMaskIntoConstraints = false
midView.addSubview(thisCard)

//set the height and width constraints
let widthConstraint = NSLayoutConstraint(item: thisCard, attribute: .Width, relatedBy: .Equal, toItem: midView, attribute: .Width, multiplier: 0.125, constant: 0)
let heightConstraint = NSLayoutConstraint(item: thisCard, attribute: .Height, relatedBy: .Equal, toItem: midView, attribute: .Height, multiplier: 0.125, constant: 0)
midView.addConstraints([heightConstraint, widthConstraint])

//set the horizontal position

if (columnCounter > 0) {

// card is not in the first column
let cardOnTheLeft = cards[index-1]

let leftSideConstraint = NSLayoutConstraint(item: thisCard, attribute: .Left, relatedBy: .Equal, toItem: cardOnTheLeft, attribute: .Right, multiplier: 1, constant: 0)

//add constraint to the contentView
midView.addConstraint(leftSideConstraint)

} else {

//card is in the first column

let leftSideConstraint = NSLayoutConstraint(item: thisCard, attribute: .Left, relatedBy: .Equal, toItem: midView, attribute: .Left, multiplier: 1, constant: 0)

//add constraint to the contentView
midView.addConstraint(leftSideConstraint)

}


//set the vertical position

if (rowCounter > 0) {

// card is not in the first row
let cardOnTop = cards[index-8]

let topConstraint = NSLayoutConstraint(item: thisCard, attribute: .Top, relatedBy: .Equal, toItem: cardOnTop, attribute: .Bottom, multiplier: 1, constant: 0)

// add constraint to the contentView
midView.addConstraint(topConstraint)

} else {

//card is in the first row

let topConstraint = NSLayoutConstraint(item: thisCard, attribute: .Top, relatedBy: .Equal, toItem: midView, attribute: .Top, multiplier: 1, constant: 0)

//add constraint to the contentView
midView.addConstraint(topConstraint)

}



//increment the column counter
columnCounter = columnCounter+1

//if the column counter reaches the fifth column reset it and increase the row counter
if (columnCounter >= 8) {
columnCounter = 0
rowCounter = rowCounter+1
}




} // end of the loop



}

Answer

You say this is failing when you run it a second time. That is because you apparently have rowCounter and columnCounter declared as properties and you are not setting rowCounter and columnCounter back to 0 each time layoutCards() is called.

Make rowCounter and columnCounter be local variables to layoutCards():

func layoutCards() {
    var rowCounter = 0
    var columnCounter = 0

    //  create cards array with several elements
    var cards = (1...64).map { _ in UIView() }// array with several cards