0
votes

I want my UITableViewCell to expand in size when tapped.

The layout of the cell is quite straightforward. Within the UITableViewCell is a UILabel. The UILabel is constrained to the UITableViewCell with top, bottom, left and right anchors.

I also have two stored properties. labelExpandedHeightConstraint stores the UILabel's height constraint for when the label is expanded. labelCompactHeightConstraint stores the UILabel's height constraint for when the label is compacted. Notice that labelCompactHeightConstraint is initially set to active.

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        let spacing = 8

        self.addSubview(self.labelView)
                
        self.labelView.translatesAutoresizingMaskIntoConstraints = false

        self.labelView.topAnchor.constraint(equalTo: self.topAnchor, constant: spacing).isActive = true
        self.labelView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -1 * spacing).isActive = true
        self.labelView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: spacing).isActive = true
        self.labelView.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -1 * spacing).isActive = true
                
        self.labelExpandedHeightConstraint = self.labelView.heightAnchor.constraint(equalToConstant: 120)
        self.labelCompactHeightConstraint = self.labelView.heightAnchor.constraint(equalToConstant: 80)
        self.labelCompactHeightConstraint.isActive = true
}

The expand() function below is called whenever the user taps a UITapGestureRecognizer. This function is very simple. It expands the cell by disabling labelCompactHeightConstraint and enabling labelExpandedHeightConstraint.

@objc func expand() {
        self.labelCompactHeightConstraint.isActive = false
        self.labelExpandedHeightConstraint.isActive = true
        self.layoutIfNeeded()
    }

The problem is that when the expand() function is called, the UITableViewCell and its contents do not change in size. It is not until the user scrolls the cell off the screen, and then scrolls it back onto the screen, that the size adjusts correctly.

How can I get the cell to expand immediately when tapped? I would also like this sizing change to be animated. I would really appreciate any suggestions. Thanks!

1

1 Answers

0
votes

You'll need to do it differently.
Something like:

tableView.beginUpdates()
// update data for cell, or if your cell is not dynamically created - update it directly
// Usually, you'll need to update your data structures 
// Reload the cell
tableView.reloadRows(at: [indexPath], with: .automatic)
tableView.endUpdates()

From what you wrote, the place to add this code is from:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
...
}

Also, note that in most cases, you should just change the content (ie. the text in the label) and not the constraint value.

Here is a minimal full example:

class ViewController: UITableViewController {
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 100
    }
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ident", for: indexPath) as! Cell
        if selections.contains(indexPath) {
            cell.height.constant = 80
        } else {
            cell.height.constant = 10
        }
        return cell
    }
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.beginUpdates()
        if selections.contains(indexPath){
            selections.remove(indexPath)
        } else {
            selections.insert(indexPath)
        }
        tableView.reloadRows(at: [indexPath], with: .automatic)
        tableView.endUpdates()
    }
    var selections = Set<IndexPath>()
}

class Cell : UITableViewCell {
    @IBOutlet var height : NSLayoutConstraint!
}

Could use the table view's multiple selection but wanted to demonstrate usage of app specific data.