How do I tell my UITableViewCell to "auto-resize" when its content changes?
Asked Answered
E

9

28

In my cell.xib, I have a label, with constraints to all its sides. I've set that label to lines = 0 and line-break = word wrap. Then, I do this to my TableView:

self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 100.0

Everything works great, and my UITableViewCell is auto-height. If the text is long, then my tableView intelligently calculates the size.

The problem is -- how do I tell my UITableView to "re-calculate" the size once the content changes in the cell?

My cell could call its delegate, and in this delegate, I'd like the TableView to re-draw the height.

Right now, the content in my cells change constantly, but the cell height never changes.

Entryway answered 13/3, 2016 at 20:31 Comment(6)
if your UITableview not resized withUITableViewAutomaticDimension then it problem with Constraints. and another way to auto resize i sugest yopu to use KeyValue Observer.Pyrene
do you meant your tableview height will change as per the height of the cells? and the issue is cell height is changing but tableview height is not changing?Scopp
Can you put the screenshot? And also do you want to increase the height of UITableViewCell or UITableView? Also, you can running on which iOS Version?Lambdoid
Also, why you are not using Prototype UITableViewCell?Lambdoid
TIMEX, not responding to anyone, he might just want to get all the possible ways of doing this. All the answer below should satisfy the question, there is not magic way to do this other than the answers below.Eades
@Entryway you can KVO for the contentSize of the UITableView, then update the UITableView frame.heightGargoyle
B
44

There is a documented way to do this. See UITableView.beginUpdates() documentation:

You can also use this method followed by the endUpdates method to animate the change in the row heights without reloading the cell.

So, the correct solution is:

tableView.beginUpdates()
tableView.endUpdates()

Also note that there is a feature that is not documented - you can add a completion handler for the update animation here, too:

tableView.beginUpdates()
CATransaction.setCompletionBlock {
   // this will be called when the update animation ends
}

tableView.endUpdates()

However, tread lightly, it's not documented (but it works because UITableView uses a CATransaction for the animation).

Beeswax answered 16/3, 2016 at 9:30 Comment(2)
Thanks Sulthan. How can I update the height of only one cell?Entryway
@Entryway This method makes the table to query the new heights and animate changes (sync with the data model). If you want to change height of only one cell, you will have to change only one height in your data model (e.g. change label.text only in one cell, not in several cells at once).Beeswax
I
7

I've found the best way to get it to check heights is to call, after whatever text change has been made, in order:

self.tableView.beginUpdates()
self.tableView.endUpdates()

This causes the tableView to check heights for all visible cells and it will cause changes to be made as needed.

Invisible answered 16/3, 2016 at 7:23 Comment(0)
T
2

I think the simplest solution is to reload that specific cell. For example:

- (void)yourDelegateMethodOfCell:(UITableViewCell *)cell {
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
    //If cell is not visible then indexPath will be nil so,
    if (indexPath) {
        [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
    }
}
Tresatrescha answered 16/3, 2016 at 5:3 Comment(0)
G
2

You can get automatic cell height by this code

tableView.beginUpdates()
// add label text update code here 
// label.numberOfLines = label.numberOfLines == 0 ? 1 : 0
tableView.endUpdates()

Below is the reference to this solution with demo :

GitHub-RayFix-MultiLineDemo

Grater answered 16/3, 2016 at 9:37 Comment(0)
T
0

I got your point, and I met the problem before.
Your cell is in AutoLayout, and you wish the cell changes by itself. Here is recommended answer for that: Using Auto Layout in UITableView for dynamic cell layouts & variable row heights , so we don't talk about that again.

So here we focus on your problem.

Since the content of your cell changes constantly, which means the content has updated. Here we suppose the content is a label. We set the label's text, and surely the label's height maybe change.

Here comes the point: How does the label's change inform the cell to update?

We use AutoLayout, surely we have to update the constraint of height for the label.

And I think it will work!

Below is the detail step:
1. We setup the constraints for the cell's subviews.(I think it's done)
2. One of the label's height is changed by itself.(I think it's done too)
3. We get the new height of the label, and update the constraint of height for the label.(what we have to do)

Teishateixeira answered 16/3, 2016 at 7:54 Comment(0)
H
0

Seems you wanted to reload the particular cell/cells based on content changes

Here we have a couple of options

1) Need to reload the entire table view .

or else

2) Reload particular cell/cells based on content changes.

But the preferred option would be reloading the particular cell,

Why because when you asked your UITableView instance to reload a couple of cells,tableview will asks its datasource(-tableView:cellForRowAtIndexPath:) to get the updated content,so that the reloaded cells will have the updated size & Updated content aswell.

Try to reload the cells when the content/height need to update based on content

Hope that helps! Happy coding :)

Havelock answered 16/3, 2016 at 9:14 Comment(0)
A
0

Take a look at this answer : Using Auto Layout in UITableView for dynamic cell layouts & variable row heights

How to achieve dynamic cell size is described very thorough there.

As a suggestion for testing try adding setNeedsLayout to:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

or

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath 
Anselme answered 17/3, 2016 at 15:29 Comment(0)
M
0

To disable the annoying tableView animation:

UIView.setAnimationsEnabled(false)
tableView.beginUpdates()
// cell.titleLabel?.text = "title"
// cell.detailTextLabel?.text = "Very long text ..."
// cell.detailTextLabel?.numberOfLines = 0
tableView.endUpdates()
UIView.setAnimationsEnabled(true)
Mascagni answered 11/2, 2021 at 1:34 Comment(0)
S
-1

You can resize your cell height by implementing below method only

 - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath{
return UITableViewAutomaticDimension;
}
Sporangium answered 16/3, 2016 at 7:39 Comment(2)
this is equivalent with self.tableView.rowHeight = UITableViewAutomaticDimensionBackbone
This only works during initialization of the cell. Once it's dequeued and data is updated, it will not resize.Dari

© 2022 - 2024 — McMap. All rights reserved.