Reputation: 811
I have a set of UILabels that are shown in the cells of a TableView. When the user touches the cell, the label expands to show all the text I've put in there instead of a two-line truncated version.
The animation and expanding works, but when I press the label again to make it shrink the TableViewCell the label is in resizes correctly, but the label does not. I've NSLog'ed the size of the label, and programmatically my code works but it is failing to draw correctly.
Here is my cellForRowAtIndexPath method:
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *sectionContents = [[self tableData] objectAtIndex:[indexPath section]];
NSString *contentForRow = [sectionContents objectAtIndex:[indexPath row]];
UILabel *label = nil;
int noOfLines;
UITableViewCell *cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"Cell"];
label = [[UILabel alloc] initWithFrame:CGRectZero];
CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
label.text = contentForRow;
if ([expandedIndexPathsArray containsObject:indexPath])
{
noOfLines = 0;
CGSize size = [contentForRow sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
label.frame = CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), MAX(size.height, 44.0f));
NSLog(@"height is now %f",label.frame.size.height);
} else {
noOfLines = 2;
CGSize size = [contentForRow sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
label.frame = CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), MIN(size.height, 44.0f));
NSLog(@"height is now %f",label.frame.size.height);
}
NSLog(@"Number of Lines: %d",noOfLines);
label.lineBreakMode = UILineBreakModeWordWrap;
label.backgroundColor = [UIColor blueColor];
label.font = [UIFont systemFontOfSize:FONT_SIZE];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
label.numberOfLines = noOfLines;
[[cell contentView] addSubview:label];
[label release];
return cell;
}
Can anybody tell me what is going on here, because I am struggling to understand it.
Thanks in advance! :D
Upvotes: 2
Views: 1221
Reputation: 7072
The code you have posted doesn't appear (as per your comment) to layer new labels over old ones. It does, however, mint a brand new cell each time the method is called. That's not the usual design pattern.
The usual pattern is to recycle cells and only create new ones if a recycled one is not available. Using this approach you do need (as per your comment) some way of keeping track of the label. (One way of doing this is shown in the snippet below.)
You have not posted your tableView:heightForRowAtIndexPath: method. Depending what is going on there, you might get odd behaviour, i.e. if the row height doesn't match the label height. It's also not clear when you are calling reloadData (or one the related methods) on the tableView. This does need to get called so iOS can refresh the cell row height. Maybe that's all OK in your code - but definitely worth checking.
I've tested the following code and it expands and reduces cells in the way I think you are trying to achieve in your question. For my convenience, this code just test to see if row matches a given number to determine whether it is expanded or not. You'll substitute [expandedIndexPathsArray containsObject:indexPath] for my ([indexPath row] == _pgSpecialRow).
I've separated the work out by adding two additional methods (although there is less code here altogether). This is partly to aid readability, and partly because the tableView:heightForRowAtIndexPath: methods needs to do the same sums as the tableView:cellForRowAtIndexPath: method
- (UITableViewCell *)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString* cellIdentifier = @"Cell";
// see if there's a cell available to recylce
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell)
{
// there's no cell to recycle, so make a new one
// add a label to it and tag the label so we can find it later
cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:cellIdentifier];
UILabel* label = [[UILabel alloc] init];
// do set up on label that doesn't vary with cell content
[label setTag: 101];
label.lineBreakMode = UILineBreakModeWordWrap;
label.backgroundColor = [UIColor blueColor];
label.font = [UIFont systemFontOfSize:FONT_SIZE];
[[cell contentView] addSubview:label];
[label release];
}
// either on a recycled cell or on the cell just created, set the contents
NSArray *sectionContents = [[self tableData] objectAtIndex:[indexPath section]];
NSString *contentForRow = [sectionContents objectAtIndex:[indexPath row]];
UILabel* label = (UILabel*)[[cell contentView] viewWithTag:101];
[self adjustLabel: label forText:contentForRow andExpanded:([indexPath row] == _pgSpecialRow)];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
- (void) adjustLabel: (UILabel*) label forText: (NSString*) text andExpanded: (BOOL) expanded;
{
label.text = text;
CGFloat height = [self heightForLabelWithText: text expanded: expanded];
label.frame = CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), height);
label.numberOfLines = expanded ? 0: 2;
}
- (CGFloat) heightForLabelWithText: (NSString*) text expanded: (BOOL) expanded;
{
CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
if (expanded)
{
return MAX([text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap].height, 44.0);
}
return MIN([text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap].height, 44.0);
}
- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *sectionContents = [[self tableData] objectAtIndex:[indexPath section]];
NSString *contentForRow = [sectionContents objectAtIndex:[indexPath row]];
// return a cell height that's big enough (with a bit of extra margin)
return [self heightForLabelWithText: contentForRow expanded:([indexPath row] == _pgSpecialRow)]+ 16.0;
}
Upvotes: 1