Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does changing the intrinsicContentSize of a UITableViewCell work?

I made a UITableView with cells that expand when you tap on them. It is modeled off the following project: https://github.com/rushisangani/TableViewCellExpand

Basically, the cell's container view has two subviews which act as containers for the expanded/contracted states - "front" and "back", each of which is constrained to the top, bottom, leading, and trailing edges of the cell's main content view. To make the cell expand or contract, I just toggle the isActive property on the bottom constraint of the front and back views. This works, but only if I reload the cell when it is tapped. If I just change the constraints and then try to call invalidateIntrinsicContentSize(), nothing happens.

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
    {
        // Expand/contract the cell and invalidate size (doesn't work)
//        let cell = tableView.cellForRow(at: indexPath) as! ExpandingCell
//        cell.tap()
//        cell.invalidateIntrinsicContentSize()

        // Keep track of the selected index and configure the expand/contract state when the cell is remade
        tableView.deselectRow(at: indexPath, animated: false)
        expandedIndexPath = indexPath
        if(!expandedIndexPathArray.contains(indexPath)){
            expandedIndexPathArray.append(indexPath)
        }
        else{
            expandedIndexPathArray = expandedIndexPathArray.filter({$0 != indexPath})
        }

        // Whenever a cell's intrinsicContentSize changes, it must be reloaded
        tableView.reloadRows(at: [indexPath], with: .none)
    }

What's going on behind the scenes? Why can't the cell recalculate its size without being reloaded?

like image 967
GoldenJoe Avatar asked Sep 11 '25 04:09

GoldenJoe


1 Answers

If you want to contract/expand cells based on their intrinsic content size, you need to do the following 3 steps:

  1. Configure the table view:

    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 44
    

    For static table view controller, you will need to implement heightForRowAtIndexPath and return UITableViewAutomaticDimension.

  2. Update cell constraints to reflect contracted/expanded state

  3. Ask the table view to reflect changes:

    tableView.beginUpdates()
    tableView.endUpdates()
    
like image 173
Rudolf Adamkovič Avatar answered Sep 13 '25 19:09

Rudolf Adamkovič