IOS - heightForRowAtIndexPath not working when scrolling

I am writing a simple iOS application using Xcode4, which uses a table view to display a list of stories (retrieved from a URL). I show the episode names as UILabels and as a table cell subtitle.

I am moving heightForRowAtIndexPath to calculate the correct height for the cells according to the length of each plot name. I am adding a shortcut to a cell in cellForRowAtIndexPath . When I run the application in the simulator, everything works out well. However: when I scroll down and scroll up, the shortcuts are messed up. They are truncated and overloaded. I debugged a bit and found that the heightForRowAtIndexPath method heightForRowAtIndexPath not start during scrolling, so the cell heights are not recounted, and therefore the text of the label overflows and becomes visualized ugly. Here is the relevant code:

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"Cell"]; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; [cell autorelease]; } /* NOTE: code to load trimmedTitle dynamically is snipped */ NSString* trimmedTitle; UIFont *cellFont = [UIFont fontWithName:@"Georgia" size:14.0]; CGSize constraintSize = CGSizeMake(280.0f, MAXFLOAT); CGSize labelSize = [trimmedTitle sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap]; UILabel* tempLabel = [[UILabel alloc] initWithFrame:CGRectMake(60, 0, 230, labelSize.height)]; tempLabel.lineBreakMode = UILineBreakModeWordWrap; tempLabel.text = trimmedTitle; tempLabel.numberOfLines = 0; [cell.contentView addSubview:tempLabel]; [tempLabel release]; return cell; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { NSString* cellText; // code to load cellText dynamically is snipped off UIFont *cellFont = [UIFont fontWithName:@"Georgia" size:14.0]; CGSize constraintSize = CGSizeMake(230.0f, MAXFLOAT); CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap]; return labelSize.height + 20; } 
+4
source share
3 answers

In such situations, I usually pre-compute the heights of all my rows, store them in an array, and then simply return those heights to heightForRowAtIndexPath . Thus, the table view knows the height of each cell, and the cells must match this height even after reuse. I don’t know how to get the cell height to be calculated before looking for when the cell will be visible and reboot, which seems too expensive.

Update : code example:

I have a method called - (void)calculateHeights that does the same calculations as in heightForRowAtIndexPath , but stores the result in my heights_ ivar mutable array:

 - (void)calculateHeights { [heights_ removeAllObjects] for (Widget *myWidget in modelWidgetArray) { NSString* cellText; // code to load cellText dynamically is snipped off UIFont *cellFont = [UIFont fontWithName:@"Georgia" size:14.0]; CGSize constraintSize = CGSizeMake(230.0f, MAXFLOAT); CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap]; [heights_ addObject:[NSNumber numberWithFloat:labelSize.height + 20.0f]]; } } 

And then in heightForRowAtIndexPath , given the view of the table from 1 section:

 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return [heights_ objectAtIndex:[indexPath row]]; } 

If there are several sections in your table view, you will need to do some math to convert to the one-dimensional array heights_ and vice versa. In addition, every time you -reloadData , you also need -calculateHeights .

+2
source

The -tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath method -tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath is called before creating the scroll view.

The purpose of calling this method before calling -tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath and does not start during scrolling is that the table view ( which is inherited from UIScrollView ) must know the entire height of the content. When a table view knows the whole height, it caches the height before you call -reloadData

Your problem means that you need to clear the contents in the -prepareForReuse cell and call -setNeedLayout to -setNeedLayout all the new content.

0
source

you can use the tag for your shortcut so as not to mess with each other

 UILabel *label= (UILabel*)[cell viewWithTag:2]; label.lineBreakMode = UILineBreakModeWordWrap; label.numberOfLines = 0; 
0
source

All Articles