2

I am trying to make an offscreen version of a cell that will later be rendered and then use

[cell.label sizeToFit];

then use the new adjusted size of the label to calculate a height like this:

 float height = cell.complishLabel.bounds.size.height;
 return 50 + height;

However, the problem I am having is that for height I always get 0 and I am not sure why.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    //Make an off screen cell
    ZSSComplishTableViewCell *cell = [[ZSSComplishTableViewCell alloc] init];

    //Which section?
    if (indexPath.section == 0) {

        //Get a statement from the datasource and assign it to the label
        NSArray *todayComplishs = [[ZSSComplishStore sharedStore] todayComplishs];
        ZSSComplish *complish = todayComplishs[indexPath.row];
        cell.complishLabel.text = complish.statement;

        //Resize label to the amount of text
        [cell.complishLabel sizeToFit];

        NSLog(@"calculated height of label: %f", cell.complishLabel.frame.size.height);
        //Get height of label
        float height = cell.complishLabel.bounds.size.height;
        return 50 + height;
    } else if (indexPath.section == 1) {

        //Get a statement from the datasource and assign it to the label
        NSArray *tomorrowComplishs = [[ZSSComplishStore sharedStore] tomorrowComplishs];
        ZSSComplish *complish = tomorrowComplishs[indexPath.row];
        cell.complishLabel.text = complish.statement;

        //Resize label to the amount of text
        [cell.complishLabel sizeToFit];

        //Get height of label
        float height = cell.complishLabel.bounds.size.height;
        return 50 + height;
    }


    return 100;


}

This is the ZSSComplishTableViewCell.m

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code
    }
    return self;
}

- (void)awakeFromNib
{
    // Initialization code
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}
shakked
  • 633
  • 6
  • 23
  • Is this NSLog correct for getting the height? `NSLog(@"calculated height of label: %f", cell.complishLabel.frame.size.width);` Should be: cell.complishLabel.frame.size.height. – klcjr89 Jul 15 '14 at 01:59
  • it's supposed to be height, sorry, i was experimenting before I posted this – shakked Jul 15 '14 at 02:01
  • Does ZSSComplishTableViewCell create it's complishLabel during init? – danh Jul 15 '14 at 02:01
  • I'm not sure. It's was designed in the interface builder and there is only the standard code in the .m file I'll post – shakked Jul 15 '14 at 02:03
  • check this http://www.engage-encore.com/index.php/2010/12/17/uilabel-size-to-fit-tex/ – Huy Nghia Jul 15 '14 at 02:10
  • log the label property, I'm guessing it doesn't have a frame/height or doesn't exist. I did this using a standard tableViewCell and it's textLabel property and its working how I assume you want yours to work: https://www.dropbox.com/s/a9jpl1p62ngmuyn/Screenshot%202014-07-14%2022.52.54.png – Mike Jul 15 '14 at 02:53

3 Answers3

0

I think when you get

NSLog(@"calculated height of label: %f", cell.complishLabel.frame.size.height);

method sizeToFit couldn't caculate complishLabel frame yet. Try to use sizeThatFit: method instead

another way to calculate your label height

Huy Nghia
  • 1,000
  • 8
  • 21
  • for the other way of calculating labelHeight that links to the outside page, the method used is deprecated – shakked Jul 15 '14 at 02:47
  • sorry, my mistake you can use boundingRectWithSize:options:attributes:context:") method instead – Huy Nghia Jul 15 '14 at 02:51
0

Here's what I found worked:

//Set a random frame
CGRect labelFrame = CGRectMake(0, 0, 263, 1000);
//make a label with that frame
        UILabel *label = [[UILabel alloc] initWithFrame:labelFrame];
//set a preferredMaxLayoutWidth to what you want it constrained to
        label.preferredMaxLayoutWidth = 263;
//configure your label
        UIFont *font = [UIFont fontWithName:@"Gill Sans" size:18];
        label.font = font;
        label.lineBreakMode = NSLineBreakByWordWrapping;
        label.text = complish.statement;
//Set the number of lines to 0 so that it will use as many as the width and font says it needs
        label.numberOfLines = 0;

//resize the label
        [label sizeToFit];

//The height will now be adjusted to the amount of text 
        float height = label.frame.size.height;

        return 50 + height;
shakked
  • 633
  • 6
  • 23
0

Calculating height of a UILabel is easy but also tricky. There are cases to cover. I was using the code below to calculate height my project. This will support iOS 6 and iOS 7 or above. I assume you'll have multiple lines in your label. Otherwise you can tweak this function to match your needs.

#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)

static CGSize sizeForTextConstrainedToSize(NSString *text, UIFont *font, CGSize maxSize)
{
    if (SYSTEM_VERSION_LESS_THAN(@"7.0")) {
        CGSize size = [text sizeWithFont:font constrainedToSize:maxSize];
        return size;
    } else {
        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
        [paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
        NSDictionary *stringAttributes = [NSDictionary dictionaryWithObjects:@[font, paragraphStyle] forKeys:@[NSFontAttributeName, NSParagraphStyleAttributeName]];
        CGRect newRect = [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:stringAttributes context:nil];
        CGSize sizeAlignedToPixel = CGSizeMake(ceilf(newRect.size.width), ceilf(newRect.size.height));

        return sizeAlignedToPixel;
    }
}

For your code above, you shouldn't calculate the height inside the heightForRowAtIndexPath, instead calculate in advance and store it in a variable to make sure there's no lag when user scrolls the tableView.

OR: use estimatedHeightForRowAtIndexPath, then you can keep your code above, but return an approximated value in the estimatedHeightForRowAtIndexPath.

I also notice that you make use of sizeToFit to get the height, which is not right. You'll always have a boundary for whatever height you want to get. In this case, it is the tableView's width. So you have to supply a maximum CGSize every time you want get a height, which is "tableView's width x MAX_INT"

thkeen
  • 1,827
  • 2
  • 13
  • 16