0

Some odd behaviour. Got a UITableview with dynamic custom cell. As part of the custom cell is a UIStackView which contains a dynamic number of buttons. These display as expected. See image 1

Image 1

However, if the tableview is quite long (lots of rows), then on scrolling it seems to start overlaping cell contents, but only at the top of the UIStackView. More I scroll, the more layers are added. See image 2 Image 2

I've emptied the UIStackView at the start of each cell creation (this topped the buttons immediately duplicating but not stopped this layering duplication on scrolling), and also tried calling prepare for resume in the customer cell. Code below.

I can't seem to work out why upon scrolling a duplication is occurring at the first row (nowhere else). And the more I scroll the more duplication occurs.

Any help appreciated

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        // gets input type (button or numerical input - selected cellView type to use
        let inputCellType = formArray[indexPath.row][3]

        if (inputCellType == "button"){
            
            guard let cell = tableView.dequeueReusableCell(withIdentifier: FormVerticalCell.reuseIdentifier, for: indexPath) as? FormVerticalCell else {
                fatalError("Unexpected Index Path")
            }
            for arrangedSubview in cell.buttonStack.arrangedSubviews {
                cell.buttonStack.removeArrangedSubview(arrangedSubview)
                }

            // Cell question label
            cell.questionLabel.textColor = .black
            cell.questionLabel.text = formArray[indexPath.row][0]
            
            cell.buttonStack.spacing = 5.0
            cell.buttonStack.axis = .vertical
            cell.buttonStack.alignment = .fill
            cell.buttonStack.distribution = .fill
            cell.buttonStack.translatesAutoresizingMaskIntoConstraints = false
            
            let centerStyle = NSMutableParagraphStyle()
            centerStyle.alignment = NSTextAlignment.center
            var ac = AttributeContainer()
            ac.font = UIFont(name: "Ariel", size: 16)
            ac.paragraphStyle = centerStyle


            let tempOptions = formArray[indexPath.row][1]
            let optionsArray = tempOptions.components(separatedBy: ",")
            
            var btnArray = [UIButton]()

            for i in 0..<optionsArray.count {

                var cfg = UIButton.Configuration.filled()

                cfg.attributedTitle = AttributedString(optionsArray[i], attributes: ac)
                cfg.baseBackgroundColor = UIColor(red:0.8, green:0.6, blue:0.0, alpha:0.1)
                cfg.baseForegroundColor = .black
               
                let handler: UIButton.ConfigurationUpdateHandler = { button in
                           switch button.state {
                           case [.selected, .highlighted]:
                               button.configuration?.baseBackgroundColor = UIColor(red:0.8, green:0.6, blue:0.0, alpha:1.0)
                               button.configuration?.baseForegroundColor = .white
                           case .selected:
                               button.configuration?.baseBackgroundColor = UIColor(red:0.8, green:0.6, blue:0.0, alpha:1.0)
                               button.configuration?.baseForegroundColor = .white
                           case .highlighted:
                               button.configuration?.baseBackgroundColor = UIColor(red:0.8, green:0.6, blue:0.0, alpha:1.0)
                               button.configuration?.baseForegroundColor = .white

                           default:
                               button.configuration?.baseBackgroundColor = UIColor(red:0.8, green:0.6, blue:0.0, alpha:0.1)
                               button.configuration?.baseForegroundColor = .black
                           }
                    }
                
                let button = UIButton(configuration: cfg)
                button.configurationUpdateHandler = handler
                button.tag = i
                
                let tempOptionsScores = formArray[indexPath.row][2]
     
                btnArray.append(button)
                cell.buttonStack.addArrangedSubview(btnArray.last!)

                button.addAction { [self] in

                    button.isSelected = true
                    let optionsScoresArray = tempOptionsScores.components(separatedBy: ",")
                    let tempScore = optionsScoresArray[button.tag]
                    scoreArrayDouble[indexPath.row] = Double(tempScore)!
                    updateScore()

                    
                    for i in 0..<btnArray.count
                        {
                            if (i != button.tag) {
                            btnArray[i].isSelected = false
                        }
                    
                    }
                    
                }
                
            }

            cell.layoutIfNeeded()
            return cell
        }


import UIKit

class FormVerticalCell: UITableViewCell {

    static let reuseIdentifier = "vertical"

    @IBOutlet var buttonView: UIView!
    @IBOutlet weak var buttonStack: UIStackView!
    @IBOutlet var questionLabel: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func prepareForReuse() {

        super.prepareForReuse()
        
        for arrangedSubview in buttonStack.arrangedSubviews {
            buttonStack.removeArrangedSubview(arrangedSubview)
            }
        
    }
    
    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

EDIT: It seems the UIButtons in the stack view are overlapping on each row after that row has scrolled off page. Basically duplicates created, but all on one point. Removing:

for arrangedSubview in buttonStack.arrangedSubviews {
                buttonStack.removeArrangedSubview(arrangedSubview)
                }

Resolves the overlapping...but still have duplicates that now extend downwards.

Overall, I need to remove the UIStackView contents due to reuse, but but using above code (removeArrangedsubview, just seems to collapse upon itself, causing the overlap.

Any ideas?

1 Answer 1

0

Simple issue:

buttonStack.removeArrangedSubview(arrangedSubview)

Wasn't sufficient to remove the buttons from the stack fully. Also had to add:

        arrangedSubview.removeFromSuperview()
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.