I have a Subtitle style UITableViewCell which height changes dynamically depending on the length of the text for each field. The problem is that the textLabel's height (CGSize size) does not increase if the label has multiple lines.
The weird part is that the detailTextLabel's height is increasing as it should (CGSize size2). The code to calculate both heights are identical.
Here is my function:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
SETLISTFMNS0Song *song = [[[selectedSetlist.sets objectAtIndex:indexPath.section] songs]objectAtIndex:indexPath.row];
CGSize size = [song.name sizeWithFont:[UIFont fontWithName:setlistFont size:labelFontSize] constrainedToSize:CGSizeMake(self.setsTable.bounds.size.width, CGFLOAT_MAX)];
NSLog(@"Label: \"%@\" \tLabel Size: %f W %f H", song.name, size.width, size.height);
NSMutableString *detail;
if ([song cover]) {
detail = [[NSMutableString alloc] initWithFormat:@"(%@ cover)", [[song cover] name]];
}
if ([song with]) {
if (!detail) {
detail = [[NSMutableString alloc] initWithFormat:@"(with %@)", [[song with] name]];
}
else {
[detail appendFormat:@" (with %@)", [[song with] name]];
}
}
if ([song info]) {
if (!detail) {
detail = [[NSMutableString alloc] initWithFormat:@"(%@)", [song info]];
}
else {
[detail appendFormat:@" (%@)", [song info]];
}
}
if (detail.length != 0) {
CGSize size2 = [detail sizeWithFont:[UIFont fontWithName:setlistFont size:detailFontSize] constrainedToSize:CGSizeMake(self.setsTable.bounds.size.width, CGFLOAT_MAX)];
size.height += size2.height;
NSLog(@"Detail Label: \"%@\" \tDetail Label Size: %f W %f H", detail, size2.width, size2.height);
}
return size.height + 5;
}
I am also setting both textLabel's numberOfLines property to 0 in cellForRowAtIndexPath to support multiple lines:
cell.textLabel.numberOfLines = 0;
cell.detailTextLabel.numberOfLines = 0;
UPDATE: Thanks to @josh I now understand why this is happening. I had the width constraints set to the width of the UITableView, which is too wide. Anyone know how to find the width of the UILabel before it is created? HA!
Thanks!
How long are the strings you're calculating the size against? I ask because you're sizeWithFont:constrainedToSize:
function is constraining to the full width of the cell, but your labels are probably not the full width of the cell.
What I suspect is happening is song.info
is just short enough that it would fit on one line if the line were the full width of the cell, and that your song detail
is long enough that it is calculating the correct number of lines, but not so long as to exceed the calculated height.
All of that to say, I think what you need to do is find out the widths of textLabel
and detailTextLabel
and set your constraints to those values.
Update - A way of calculating label widths
Since the width of the labels inside of a cell are dependent on the width of the cell, and since cell's aren't created at the time heightForRowAtIndexPath:
is called, we need to come up with a way to know the labels' widths before they the widths are set. The only way to do this is to set the widths ourselves. Here's how I would do it:
MyCell.h
#import <UIKit/UIKit.h>
@interface MyCell : UITableViewCell
+ (CGFloat)textLabelWidthForCellOfWidth:(CGFloat)cellWidth;
@end
MyCell.m
#import "MyCell.h"
@implementation MyCell
- (void)layoutSubviews {
[super layoutSubviews];
CGRect frame = self.textLabel.frame;
frame.size.width = [MyCell textLabelWidthForCellOfWidth:self.frame.size.width];
self.textLabel.frame = frame;
}
+ (CGFloat)textLabelWidthForCellOfWidth:(CGFloat)cellWidth {
// This calculation can be as complex as necessary to account for all elements that affect the label
return cellWidth - 20;
}
@end
Then in your heightForRowAtIndexPath:
implementation you can call the same class method:
CGFloat labelWidth = [MyCell textLabelWidthForCellOfWidth:self.tableView.frame.size.width]; // Since non-grouped cells are the full width of the tableView
CGSize size2 = [detail sizeWithFont:[UIFont fontWithName:setlistFont size:detailFontSize] constrainedToSize:CGSizeMake(labelWidth, CGFLOAT_MAX)];
You would create a separate Class Method (+) for each label that you need to reference.