Reputation: 1430
I have some pretty specific requirements on a layout that forces me to create a bunch of UILabels, use sizeThatFits and position them accordingly. These labels are then positioned in each cell of a UITableView. The height of the cell is determined by the size of the labels.
When generating each cell, the time it takes is acceptable. The problem comes when I add new data to the table. As the cell heights are dependent on the labels, what I currently do is create the labels for a cell and measure the resulting height. When I add 20 or so new objects, things get slow as tableView:heightForRowAtIndexPath:
get called for all new objects at once. The second problem with this approach is that since it uses a bunch of UILabels, it has to run on the main thread, so doing the calculation beforehand is not really an option.
What I need is a good way to capture the behaviour of UILabel sizeThatFits, only faster, and preferrably able to run on a background thread.
It only needs to run on iOS 7.
Upvotes: 4
Views: 2083
Reputation: 954
Use this method to pass in an NSString and it will return the estimated size for a given font (I use system font size 15 here and 320 is the cell's width):
- (CGSize)sizeOfText:(NSString*)text{
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15.0f]}];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){320, CGFLOAT_MAX}
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
return CGSizeMake(rect.size.width, rect.size.height);
}
Then in your heightForRowAtIndexPath
, this is how you set the size of the cell:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [self sizeOfText:[yourdatasource objectAtIndex:indexPath.row]].height;
}
Upvotes: 4
Reputation: 7381
iOS 7 adds the method - (CGSize)sizeWithAttributes:(NSDictionary *)attrs
to NSString
that gives you the size of a string. Under iOS7, UILabel
objects are generally very close in size to this value. It can be called on a background thread.
You can also implement tableView:estimatedHeightForRowAtIndexPath:
on your UITableViewDelegate
. Providing an estimate the height of rows can improve the user experience when loading the table view. If the table contains variable height rows, it might be expensive to calculate all their heights and so lead to a longer load time. Using estimation allows you to defer some of the cost of geometry calculation from load time to scrolling time.
Upvotes: 2