Home > database >  Swift Constraint Broken When Re-Expanding Table View
Swift Constraint Broken When Re-Expanding Table View

Time:03-11

So I have a 2 depth table view with sections and rows. When I expand the table view for the first time, everything's already good, but if I expand it for the 2nd, 3rd, .... times or scrolling when the sections expanded, then the left constraint for the rows sections is broken, for more details please see the image below:

Please see this for details

It's my 3rd time I expanding the sections. And as you can see there're 2 rows that have broken left constraint. Here's my code:

func configureCell(data: FirstDepth) {
    self.firstDepthData = data
    self.firstDepthLabel.text = data.name
    self.firstDepthLabel.centerY(inView: contentView, leftAnchor: contentView.leftAnchor, paddingLeft: 20)
}

func configureSecondCell(data: SecondDepth) {
    self.secondDepthData = data
    self.firstDepthLabel.text = data.name
    self.firstDepthLabel.centerY(inView: contentView, leftAnchor: contentView.leftAnchor, paddingLeft: 50)
}

So the table view will call configureCell for the sections, and configureSecondCell for the rows, I've read maybe this is because of re-initialize the constraints, but how to only update the constant?

If needed, here's my code for the table view cell:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: CellFirstDepth.id, for: indexPath) as! CellFirstDepth
    
    if let firstDepthData = self.firstDepthData {
        if indexPath.row == 0 {
            // Call Cell for sections
            cell.configureCell(data: firstDepthData[indexPath.section])
        } else {
            // Call Cell for rows
            cell.configureSecondCell(data: firstDepthData[indexPath.section].child[indexPath.row - 1])
        }
    }
    return cell
}

And this is my centerY function, just a code to make the element center to Y axis, and add anchor to left/right:

func centerY(inView view: UIView, leftAnchor: NSLayoutXAxisAnchor? = nil, rightAnchor: NSLayoutXAxisAnchor? = nil, paddingLeft: CGFloat? = nil, paddingRight: CGFloat? = nil, constant: CGFloat? = 0) {
    translatesAutoresizingMaskIntoConstraints = false
    
    centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: constant!).isActive = true
    
    if let leftAnchor = leftAnchor, let paddingLeft = paddingLeft {
        self.leftAnchor.constraint(equalTo: leftAnchor, constant: paddingLeft).isActive = true
    } else if let rightAnchor = rightAnchor, let paddingRight = paddingRight {
        self.rightAnchor.constraint(equalTo: rightAnchor, constant: -paddingRight).isActive = true
    }
}

CodePudding user response:

You haven't shown us what your .centerY(...) function does, but pretty safe guess as to the problem.

It looks like you are adding a .leftAnchor constraint with a constant of 20, and then the cell get's reused and you're adding another .leftAnchor constraint with a constant of 50.

You need to edit your cell code to use a single constraint, and update its .constant property, instead of adding multiple constraints.


Edit

With a little searching, you can find many complete examples, but here's the general idea.

In your cell class, add this var property:

var labelLeftConstraint: NSLayoutConstraint!

Then, in your cell class initialization, create that constraint:

labelLeftConstraint = self.firstDepthLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 0)
labelLeftConstraint.isActive = true

And, change your configure funcs like this:

func configureCell(data: FirstDepth) {
    self.firstDepthData = data
    self.firstDepthLabel.text = data.name
    labelLeftConstraint.constant = 20
    //self.firstDepthLabel.centerY(inView: contentView, leftAnchor: contentView.leftAnchor, paddingLeft: 20)
}

func configureSecondCell(data: SecondDepth) {
    self.secondDepthData = data
    self.firstDepthLabel.text = data.name
    labelLeftConstraint.constant = 50
    //self.firstDepthLabel.centerY(inView: contentView, leftAnchor: contentView.leftAnchor, paddingLeft: 50)
}

Now you will have only a single constraint, and your code will be setting its .constant instead of creating it over and over (which is what causes the problem).

  • Related