How to make UITableView row height respond to user

2019-04-15 23:46发布

问题:

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?

回答1:

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);


回答2:

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;
 }