Gilad Schickler
Gilad Schickler

Reputation: 135

how to add stackViews to UITableViewCell?

i am trying to dynamically create UIButtons inside UIStackViews that will load into a TableViewCell.

i have two arrays that hold String values:

array_1 = ["a" , "b" , "c"]
array_2 = ["x" , "y" , "z"]

i have a function that creates a UIButton, and a function that generates an array of UIButton arrays that holds one value from 'array_1' plus all the values from 'array_2' (i.e: [[a,x,y,z], [b,x,y,z], [c,x,y,z]])

    func createButton(title : String) -> UIButton {
    let newButton = UIButton(type: .system)
    newButton.setTitle(title, for: .normal)
    newButton.backgroundColor = UIColor.lightGray
    return newButton
}

    func generateButtons() -> [[UIButton]]{
    var topButtonArray = [UIButton]()
    var buttomButtonArray = [UIButton]()
    var finalButtonArray = [[UIButton]]()

    for title in array_1 {
        topButtonArray += [createButton(title: title)]
    }
    for title in array_2 {
        buttomButtonArray += [createButton(title: title)]
    }

    for button in topButtonArray {
       finalButtonArray += [[button]+buttomButtonArray]
    }

   return finalButtonArray
}

now i have a function that creates a UIStackView which its arranged subviews are the button arrays, and one that generates an array of UIStackViews that hold those stackViews with buttons

    func createStackView(subViews : [UIButton]) -> UIStackView{
    let stackView = UIStackView(arrangedSubviews: subViews)
    stackView.axis = .vertical
    stackView.distribution = .fillEqually
    stackView.alignment = .fill
    stackView.translatesAutoresizingMaskIntoConstraints = false
    stackView.spacing = 5
    return stackView
}


    func generateStackViewArray() -> [UIStackView] {
    var stackViewArray = [UIStackView]()
    let finalButtonArray = generateButtons()
    for buttons in finalButtonArray{
        stackViewArray += [createStackView(subViews: buttons)]
    }
    return stackViewArray
}

finally, i want to load those UIStackViews into individual UITableViewCells

    override func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return array_1.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "First")!
    cell.contentView.addSubview(generateStackViewArray([indexPath.row])
    return cell
}

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let screenSize : CGRect = UIScreen.main.bounds
    let screenHeight = screenSize.height
    let relativeCellSizeDefault = screenHeight / CGFloat (array_1.count)

    return relativeCellSizeDefault
}

right now my final result is a UITableView, with 3 cells (just as i want) but in the first and second cell i can only see the first button (i.e : a/ b) but in the third cell i get what i want to happen (i.e: a,x,y,z):

finalResultImage

i tried figuring out the problem with my logic but i can't seem to find the answer why it only loads the entire button array in the last cell.

also, i am a beginner so there might be some redundancy or i might not be using best practice for some stuff - feel free to correct me and thank you very much for helping

Upvotes: 1

Views: 623

Answers (1)

beyowulf
beyowulf

Reputation: 15321

Classes in swift are pass by reference not pass by value. UIButton is a class. The way your code is written currently you are only creating one instance of button "a", button "b", and button "c". But those instances have been added to multiple arrays which are then used to populate multiple stack views. So button "a" is added to stack view "x", but then is added to stack view "y", when this happens it is removed from stack view "x" because a UIView can only have one super view at a time. This happens again when it is added to stack view "z". You need to change your code so you are instantiating new instances for of the "a", "b", and "c" buttons for each cell. Something like:

func generateButtons() -> [[UIButton]]
{
    var topButtonArray = [UIButton]()
    var finalButtonArray = [[UIButton]]()

    for title in array_1
    {
        topButtonArray.append(createButton(title: title))
    }

    for button in topButtonArray
    {
        var buttonArray = [UIButton]()
        buttonArray.append(button)

        for title in array_2
        {
            buttonArray.append(createButton(title: title))
        }
        finalButtonArray.append(buttonArray)
    }

    return finalButtonArray
}

Upvotes: 1

Related Questions