Reputation: 2766
I have a UITableView that has custom UITableViewCells, which are comments from the users. Right now, I have the cells 115.0f high, but I want the height to changed based on how long the comment is. If the comment is more than three lines, I want the user to be able to select the cell, and the cell to expand to show the whole comment. I have been using the [UIView animateWithDuration: completion:
method to expand the cell, but I don't know how to figure out the correct size the cell should be based on how long the text is. Can someone help me out? Here is some code:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0)
{
return 480;
}
else
{
if (self.cellType == 0)
{
return 115;
}
else
{
return 75;
}
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row > 0)
{
NSIndexPath *path = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:path];
if ([cell isKindOfClass:[CommentCell class]])
{
CommentCell *cell = (CommentCell *)[tableView cellForRowAtIndexPath:indexPath];
UILabel *label = cell.commentBodyLabel;
NSString *theText = label.text;
CGSize constraintSize = CGSizeMake(label.frame.size.width, label.frame.size.height);
CGSize labelSize = [theText sizeWithFont:label.font constrainedToSize:constraintSize lineBreakMode:label.lineBreakMode];
CGFloat labelHeight = labelSize.height;
int numLines = (int)(labelHeight/label.font.leading);
NSLog(@"there are %i lines", numLines);
NSLog(@"The text height is %f", labelHeight);
if (numLines == 3)
{
//This is where I should expand the cell
}
}
Upvotes: 4
Views: 3116
Reputation: 9915
One method is to instantiate prototype cells and have them calculate their dynamic height based on the given data. This method lets you rely on the storyboard layout (if you're using storyboards) without having to hard-code knowledge of your cell's configuration in the view controller.
EDIT I added a working example of cells with dynamic height labels using TLIndexPathTools, which automatically calculates the dynamic heights for you if your cell implements the TLDynamicHeightView
protocol. See the "Dynamic Height" example project. The height calculation is done in the cell like this:
@interface DynamicHeightCell ()
@property (nonatomic) CGSize originalSize;
@property (nonatomic) CGSize originalLabelSize;
@end
@implementation DynamicHeightCell
- (void)awakeFromNib
{
[super awakeFromNib];
self.originalSize = self.bounds.size;
self.originalLabelSize = self.label.bounds.size;
}
- (void)configureWithText:(NSString *)text
{
self.label.text = text;
[self.label sizeToFit];
}
#pragma mark - TLDynamicSizeView
- (CGSize)sizeWithData:(id)data
{
[self configureWithText:data];
CGSize labelSize = self.label.bounds.size;
CGSize size = self.originalSize;
size.width += labelSize.width - self.originalLabelSize.width;
size.height += labelSize.height - self.originalLabelSize.height;
return size;
}
@end
In essence, you remember the original sizes when the cell is awoken from the storyboard. Then when the calculation is performed, call sizeToFit
on the label and use the new size to calculate a height delta and add it to the original height. In the storyboard, you'll need to set the label's width to the desired width and set the number lines to 0.
On the view controller side, if you're using TLIndexPathTools
, you just need to set up the data model with an array of strings and set the label on the cells. The prototypes and size calculations are done automatically by the base TLTableViewController
class. If you don't want to use TLIndexPathTools
, pulling bits from TLTableViewController
should get you going.
@implementation DynamicHeightTableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.indexPathController.items = @[
@"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
@"Fusce ac erat at lectus pulvinar porttitor vitae in mauris. Nam non eleifend tortor.",
@"Quisque tincidunt rhoncus pellentesque.",
@"Duis mauris nunc, fringilla nec elementum nec, lacinia at turpis. Duis mauris nunc, fringilla nec elementum nec, lacinia at turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.",
];
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
NSString *item = [self.indexPathController.dataModel itemAtIndexPath:indexPath];
DynamicHeightCell *dynamicCell = (DynamicHeightCell *)cell;
[dynamicCell configureWithText:item];
}
Upvotes: 1
Reputation: 21003
Take a look into NSString UIKit Additions
You are specifically interested in sizeWithFont:constrainedToSize:lineBreakMode:
Set CGSize.width
of the constrainedToSize property to the width of your cell/label area. And then set the CGSize.height
to a very large number, probably CGFLOAT_MAX
. The idea is that you are saying "Hey, this label has to fit in an area that is a static width but it can go on vertically forever. So, tell me how high this label is actually going to be given the information I gave you."
NSString *comment = @"Some really long comment that does not fit in the standard cell size. This comment will be wrapped by word. Some more words to make this longer...";
CGSize renderedSize = [comment sizeWithFont:myFont constrainedToSize:CGSizeMake(kCellWidth, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
renderedSize.height
is the value you would return for (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
Upvotes: 1