I would like the UITableView
's row height to respond to changes in the user's preferred text size. For example, when the preferred text size increases, I would like to increase the row height by a proportional amount. Here's what I have so far:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.tableView reloadData];
// observe when user changes preferred text size
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(preferredContentSizeChanged:) name:UIContentSizeCategoryDidChangeNotification object:nil];
}
- (void)preferredContentSizeChanged:(NSNotification *)notification
{
[self.tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath];
// leverage Text Kit's Dynamic Type
cell.textLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
cell.textLabel.text = @"All work and no play...";
return cell;
}
So what's the best way to calculate a row height that reflects the user's preferred text size?
I have recently accomplished this and found it to be very simple. Instead of using sizeWithFont:
you should use the new boundingRectWithSize:options:attributes:context
method in iOS 7.
Set up your table view cell as usual and specify the preferredFontForTextStyle:
on your text label as such:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:TableViewCellIdentifier forIndexPath:indexPath];
//set your table view cell content here
[[cell textLabel] setText:@"Lorem ipsum dolour sit amet."];
[[cell textLabel] setNumberOfLines:0];
[[cell textLabel] setLineBreakMode:NSLineBreakByWordWrapping];
[[cell textLabel] setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleBody]];
return cell;
}
Then to correctly determine the size of the text label, evaluate the boundingRectWithSize:options:attributes:context
to calculate the required height.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
//add your table view cell content here
NSString *string = @"Lorem ipsum dolor sit amet.";
NSDictionary *attributes = @{NSFontAttributeName: [UIFont preferredFontForTextStyle:UIFontTextStyleBody]};
CGRect frame = [string boundingRectWithSize:CGSizeMake(CGRectGetWidth(tableView.bounds), CGFLOAT_MAX) options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) attributes:attributes context:nil];
return ceilf(CGRectGetHeight(frame);
}
You may want to subclass your table view cell also to listen for UIContentSizeCategoryDidChangeNotification
notifications at which point you can update your UI when the user changes their preferences in Settings.app
- (void)contentSizeCategoryDidChangeNotificationHandler:(NSNotification *)notification
{
[[self textLabel] setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleBody]];
}
Should you require additional padding around the text label, you can define a constant value such as
static CGFloat const TableViewCellPadding = 10.0;
With this in place, you can either add a constant value to the value returned from tableView:heightForRowAtIndexPath:
return (ceilf(CGRectGetHeight(frame) + TableViewCellPadding);
Or you could inset the frame returned from boundingRectWithSize:options:attributes:context
as such:
CGRect frame = [string boundingRectWithSize:CGSizeMake(CGRectGetWidth(tableView.bounds), CGFLOAT_MAX) options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) attributes:attributes context:nil];
frame = CGRectInset(frame, 0.0, TableViewCellPadding);
use this method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *fieldLabel = labelCell.textLabel.text;
CGSize textSize = [fieldLabel sizeWithFont:[UIFont fontWithName:@"Georgia" size:17.0f] constrainedToSize:CGSizeMake([UIScreen mainScreen].bounds.size.width-20, MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping];
float newHeight = textSize.height+22.0f;
return newHeight;
}
Add below code to cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath];
UILabel *lblfield=[[UILabel alloc] init];
NSString *fieldLabel=[NSString stringWithFormat:@"%@",labelCell.textLabel.text];
CGSize textSize = [fieldLabel sizeWithFont:[UIFont fontWithName:@"Georgia" size:17.0f] constrainedToSize:CGSizeMake([UIScreen mainScreen].bounds.size.width-20, MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping];
float newHeight = textSize.height+22.0f;
lblfield.frame=CGRectMake(10, 0, [UIScreen mainScreen].bounds.size.width, newHeight);
lblfield.backgroundColor=[UIColor clearColor];
lblfield.text=strusername;
[cell addSubview:lblfield];
return cell;
}