Reason
Reason

Reputation: 1430

Need a faster way to calculate UILabel sizeThatFits

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

Answers (2)

JMarsh
JMarsh

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

Fruity Geek
Fruity Geek

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.

https://developer.apple.com/library/ios/documentation/UIKit/Reference/NSString_UIKit_Additions/Reference/Reference.html

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

Related Questions