iosswiftuitableviewios-autolayout

Have autolayout CHANGE the height of a cell, already on screen, in a dynamic height cell table?


Nowadays fortunately it's trivial to have an iOS table where every cell has a dynamic height. So in the cell vertical constraints ..

---- top of content view
- vertical constraint to
-- UILabel, with, .lines set to zero
- vertical constraint to
---- bottom of content view

Assume the UILabel texts vary greatly one word, 20 words, 100 words,

In the table set

    tableView.rowHeight = UITableView.automaticDimension
    tableView.estimatedRowHeight = 200 // say

and you're done, these days it works perfectly of course.

However, I had the common situation where you load the table, imagine ten cells.

I populate the UILabel with "Loading..."

Only then - say, a second or two later - do we get the information for the text content. It arrives say a second later and the cell changes the text to "Some long text .. with many lines".

In fact I was surprised to learn it seems UITableView does NOT handle this. The cell in question gets stuck on the original short height.

So, after the larger text is set, I tried all permutations of the usual:

        maintext.sizeToFit()
        
        contentView.layoutSubviews()
        contentView.layoutIfNeeded()

on the cell, doesn't work.

I tried sending a setNeedsLayout and/or layoutIfNeeded to the table itself, doesn't work.

I thought about .reloadData() on the table itself but - doh - that would again trigger the content being drawn from the server and loaded again, so that's not ideal.

Please note that:

  1. Obviously there are any number of workarounds for the specific example such as not using dynamic data

  2. I am completely aware how to manually animate the height of one cell (like when you "expand" one to show something else when the user taps)

This question is about autolayout and table view - which, thanks Apple, nowadays flawlessly handles completely dynamic cell heights involving UILabels with lines zero.

But what about if the text in such a label changes?

It seems that the table view system does NOT handle this.

Surely there's a way?


Solution

  • When the content of a cell changes the layout (in this case, the height) you must inform the table view that the layout has changed.

    This is commonly done with either:

    tableView.beginUpdates()
    tableView.endUpdates()
    

    or:

    tableView.performBatchUpdates(_:completion:)
    

    Why is that not triggered automatically?

    I suppose it could be to allow you to do your own animation, or you may want to delay the update, or some other reason that doesn't come to mind at the moment.

    Or, it may be due to maintaining backward compatibility?

    I don't know. I imagine Apple could tell us...