I have a UITableview
with multiple reusable TableViewCells.
In one cell I have a UITextView
, that resizes itself to fit its content. Now I \"just\
You can only resize a UITableViewCell in tableView:heightForRowAtIndexPath:
delegate method.
You have to estimate what the size of the text will be when that method is called for every row when the tableView is loaded.
This is what I did to solve the problem.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString * yourText = self.myArrayWithTextInIt[indexPath.row]; // or however you are getting the text
return additionalSpaceNeeded + [self heightForText:yourText];
}
-(CGFloat)heightForText:(NSString *)text
{
NSInteger MAX_HEIGHT = 2000;
UITextView * textView = [[UITextView alloc] initWithFrame: CGRectMake(0, 0, WIDTH_OF_TEXTVIEW, MAX_HEIGHT)];
textView.text = text;
textView.font = // your font
[textView sizeToFit];
return textView.frame.size.height;
}
EDIT
While I used this solution for a while, I found a more optimal one that I would recommend using as it doesn't require allocating an entire textView in order to work, and can handle text greater than 2000.
-(CGFloat)heightForTextViewRectWithWidth:(CGFloat)width andText:(NSString *)text
{
UIFont * font = [UIFont systemFontOfSize:12.0f];
// this returns us the size of the text for a rect but assumes 0, 0 origin
CGSize size = [text sizeWithAttributes:@{NSFontAttributeName: font}];
// so we calculate the area
CGFloat area = size.height * size.width;
CGFloat buffer = whateverExtraBufferYouNeed.0f;
// and then return the new height which is the area divided by the width
// Basically area = h * w
// area / width = h
// for w we use the width of the actual text view
return floor(area/width) + buffer;
}
You need you implement heightForRowAtIndexPath
.
Say that the data that is to be displayed in the textView is stored in a NSArray.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat cellheight = 30; //assuming that your TextView's origin.y is 30 and TextView is the last UI element in your cell
NSString *text = (NSString *)[textArray objectAtIndex:indexpath.row];
UIFont *font = [UIFont systemFontOfSize:14];// The font should be the same as that of your textView
CGSize constraintSize = CGSizeMake(maxWidth, CGFLOAT_MAX);// maxWidth = max width for the textView
CGSize size = [text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
cellHeight += size.height; //you can also add a cell padding if you want some space below textView
}
This thread has been quite a while, but in iOS 8 UITableViewAutomaticDimension
was introduced. You have to set constraints from the top to the bottom of the cell like a scroll view to make this work. But after that, just add the following code to viewDidLoad()
:
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 122.0
Make sure your estimated height is as close as possible to the real thing otherwise you'll get some buggy scrolling.
I favor this solution of Jure
textView.scrollEnabled
Set
table.rowHeight = UITableViewAutomaticDimension;
tableView.estimatedRowHeight = 44;
If finally, your code not works, then use this instead
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 44;
}
Implement UITextViewDelegate
like this:
- (void)textViewDidChange:(UITextView *)textView {
CGPoint currentOffset = self.tableView.contentOffset;
[UIView setAnimationsEnabled:NO];
[self.tableView beginUpdates];
[self.tableView endUpdates];
[UIView setAnimationsEnabled:YES];
[self.tableView setContentOffset:currentOffset animated:NO];
}
As @Rob Norback said, There is something called UITableViewAutomaticDimension
.
For Swift, The easiest way to resize content from UITableViewCell on the fly is to just add this.
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
Adding these two methods to the ViewController with UITableViewAutomaticDimension should do the trick. It has worked for me when embedding a UITextView inside of a UITableViewCell with variable length text.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}