I have a UITextView in a UITableViewCell contentview and allow the cell to autoresize so that the entered text is fully shown - what I am trying to accomplish is an autoresizing cell like the native iOS4 Contacts app has, when you enter "notes" for contact - i.e. when the contentSize of the textView changes - I call reloadRowsAtIndexPaths and in the delegate's heightForRowAtIndexPath I provide the new height for row - this does the job, however it is not nice and smooth like the contact's app - I am almost sure Apple uses some undocumented trick in that app to make the cell's contentView expand smooth and animated without calling reloadRowsAtIndexPaths. My question is how would you suggest to implement such functionality? I hope I didn't miss any details in explanation.
Asked
Active
Viewed 1.3k times
14
-
Have you tried using UIView's animations? I never used them for this, but that might work. – Jukurrpa Sep 20 '10 at 11:28
-
yes, I've tried some UIView animations for the inner content, it kinda smoothers the process, but I wonder if there is a way to not use reloadRowsAtIndexPaths, seems there is no exposed method for that. – justadreamer Sep 20 '10 at 12:44
2 Answers
16
Try this code below, it will be help. You don't have to use any reload functions like reloadRowsAtIndexPaths.
// textview delegate
- (void)textViewDidChange:(UITextView *)textView {
if (contentView.contentSize.height > contentRowHeight) {
contentRowHeight = contentView.contentSize.height;
[theTableView beginUpdates];
[theTableView endUpdates];
[contentView setFrame:CGRectMake(0, 0, 300.0, contentView.contentSize.height)];
}
}
// tableview delegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat height;
if (indexPath.row == 0)
height = kTitleRowHeight;
else
height = contentRowHeight;
return height;
}

ohtwo
- 170
- 8
-
That's property of UITableViewCell. UITextView is added in this property. [cell.contentView addSubview:textView]; – ohtwo Oct 10 '10 at 12:03
-
I'm using this solution in my app and it is working 100% on the iPhone, but on the iPad it is not: when the user types more than one line of text, the `UITableViewCell` gets taller as it is supposed to, but the `UITextView` actually moves *up*, so that the first line of text is above the top of the `UITableViewCell`--and hidden. Any ideas of how to solve this on the iPad? – Jason Oct 24 '10 at 07:18
-
PS I have posted my code for this at http://stackoverflow.com/questions/4015557/uitextview-in-a-uitableviewcell-smooth-auto-resize-works-on-iphone-but-not-ipad – Jason Oct 26 '10 at 02:34
-
@Jason: My iPad app worked as you describe until I put the contentView setFrame:... message in. Make sure that is there. – Daniel T. Mar 06 '12 at 23:06
12
I found the best way to solve this.
First off, of course, you're going to want to create your UITextView and add it to your cell's contentView. I created an instance variable of UITextView called "cellTextView" Here is the code that I used:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
if (!cellTextView) {
cellTextView = [[UITextView alloc] initWithFrame:CGRectMake(5.0, 5.0, cell.bounds.size.width - 30.0, cell.bounds.size.height - 10.0)]; // I use these x and y values plus the height value for padding purposes.
}
[cellTextView setBackgroundColor:[UIColor clearColor]];
[cellTextView setScrollEnabled:FALSE];
[cellTextView setFont:[UIFont boldSystemFontOfSize:13.0]];
[cellTextView setDelegate:self];
[cellTextView setTextColor:[UIColor blackColor]];
[cellTextView setContentInset:UIEdgeInsetsZero];
[cell.contentView addSubview:cellTextView];
return cell;
}
Then, create an int variable called numberOfLines and set the variable to 1 in your init method. Afterwards, in your textViewDelegate's textViewDidChange method, use this code:
- (void)textViewDidChange:(UITextView *)textView
{
numberOfLines = (textView.contentSize.height / textView.font.lineHeight) - 1;
float height = 44.0;
height += (textView.font.lineHeight * (numberOfLines - 1));
CGRect textViewFrame = [textView frame];
textViewFrame.size.height = height - 10.0; //The 10 value is to retrieve the same height padding I inputed earlier when I initialized the UITextView
[textView setFrame:textViewFrame];
[self.tableView beginUpdates];
[self.tableView endUpdates];
[cellTextView setContentInset:UIEdgeInsetsZero];
}
Finally, paste this code into your heightForRowAtIndexPath method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
float height = 44.0;
if (cellTextView) {
height += (cellTextView.font.lineHeight * (numberOfLines - 1));
}
return height;
}

Hector Matos
- 1,046
- 7
- 9
-
1yep, this works great +1. Also, by storing the numberOfLines in an NSArray at index = indexPath.row with the textView.tag set at the indexPath.row, then it makes multiple UITextviews in many cells change with the text size in each cell. – Rambatino Jun 15 '13 at 15:38
-
Thanks! And an easy fix to that would be to find a different way of identifying which textView you want to resize. This code was tailored to work with one textView per cell. – Hector Matos Jun 17 '13 at 18:04
-
-
1Okay let me rethink as to what I did here: So for each textView in each cell, have a different 'numberOfLines' integer variable in each element of the NSArray. So define your array (lets say for two uitextviews in two different uitableviewcells) @[@numberOfLines1,@numberOfLines2];. Now you can access each different variable and change it's value depending upon the indexPath.row of the cell you are in. – Rambatino Nov 02 '13 at 20:41
-
@Ravin455 is that sufficient? If you have any other questions just post on here. – Rambatino Nov 02 '13 at 20:56
-
@MarkRamotowski Ok I think I get it now, but then how would you do this if you have a dynamic amount of cells and therefore textViews. How would you go about that? – Souljacker Nov 03 '13 at 12:16
-
1It depends whether you have multiple sections in the tableView, if you do, then I would suggest using a separate array for each section, if you don't then one array would be sufficient. You would need a method to increase and decrease your array depending upon the dynamic number of cells but as long as your array is dynamic with each cell represented by an ordered value in your array you should be okay. Then modify your height (with heightForRowAtIndexPath) by returning [yourArray[indexPath.row] intValue]; – Rambatino Nov 03 '13 at 14:02
-
Yeah I'm doing this with CoreData (MagicalRecord to be specific) with a section name keypath specified that automatically sorts the cells into place. Do you think there is a better way to do this other than the method that is shown on this question? – Souljacker Nov 05 '13 at 12:58
-
Why do you use (numberOfLines - 1) ? Shouldn´t all rows be part of the calculation? (Maybe a stupid question?) – Johan Karlsson Jan 10 '14 at 14:51