Anil
Anil

Reputation: 2438

UITableViewCell lays out properly only on scroll

I have a UITableView with custom UITableViewCells. The cell needs to be of different heights as per the text I receive from the server. I change the height accordingly as follows:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == 0)
        return [self getHeightOfQuestion];
    else if (indexPath.row == 1)
        return 64.0f;
    else // ****** this is the cell in question!
        return [self getHeightOfAnswerAtIndexPath:indexPath];
    return 300.0f;
}

]- (CGFloat) getHeightOfAnswerAtIndexPath:(NSIndexPath*) indexPath
{
    CGRect answerFrame = CGRectZero;
    if ([QXTUtility currentOsVersion] >= 7.0f)
    {
        answerFrame = [[[[self.answerDetails objectForKey:kAnswers] objectAtIndex:indexPath.row-2] objectForKey:kAnswerText] boundingRectWithSize:CGSizeMake(242.0f, 900.0f) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont fontWithName:@"Roboto-Light" size:14.0f]} context:nil];
    }
    else
    {
        CGSize answerSize = [[[[self.answerDetails objectForKey:kAnswers] objectAtIndex:indexPath.row-2] objectForKey:kAnswerText] sizeWithFont:[UIFont fontWithName:@"Roboto-Light" size:14.0f] constrainedToSize:CGSizeMake(242.0f, 500.0f) lineBreakMode:NSLineBreakByTruncatingTail];
        answerFrame.size = answerSize;
    }
    NSLog(@"Frame %@", NSStringFromCGRect(answerFrame));

    return answerFrame.size.height + 50;
}

It works fine on iOS6. But in iOS7, I get following output:

enter image description here

But if I scroll the UITableView again, the cell lays out perfectly like so:

enter image description here

Here's my cellForRowAtIndexPath:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *answerCellIdentifier = @"QXTAnswerCell";

    QXTAnswerCell *answerCell = (QXTAnswerCell *)[tableView dequeueReusableCellWithIdentifier:answerCellIdentifier];
    if (answerCell == nil)
    {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"QXTAnswerCell" owner:self options:nil];
        answerCell = [nib objectAtIndex:0];
    }
    [self setDataToAnswerCell:answerCell AtIndexPath:indexPath];
    [self layoutAnswerCell:answerCell AtIndexPath: indexPath];
    [answerCell setNeedsLayout];
    return answerCell;

}

- (void) layoutAnswerCell:(QXTAnswerCell*) answerCell
              AtIndexPath:(NSIndexPath*) indexPath
{
    CGRect answerCellFrame = answerCell.answer.frame;
    answerCellFrame.origin.y = answerCell.name.frame.origin.y + answerCell.name.frame.size.height + 6;
    if ([QXTUtility currentOsVersion] >= 7.0f)
    {
        answerCellFrame.size.height += 30.0f;
        answerCell.answer.lineBreakMode = NSLineBreakByWordWrapping;
    }
    answerCell.answer.frame = answerCellFrame;
    dispatch_async(dispatch_get_main_queue(), ^{
        [answerCell setNeedsLayout];
    });
}

Please help me out. I'm calling a reload data once the answer's data source is populated. Thanks.

UPDATE

Just found out the first reloadData is not called once the answers are received from the server.

// Delegate from Network Class
- (void) answersReceivedWithDetails:(id)answerDetails
{
    NSLog(@"Answer Details %@", answerDetails);
    self.answerDetails = [[NSMutableDictionary alloc] initWithDictionary:answerDetails];
    [self.tableView reloadData];
    [self.tableView setNeedsDisplay];
}

Here's the constraints of the cell:

enter image description here

Upvotes: 3

Views: 197

Answers (2)

Anil
Anil

Reputation: 2438

Here's what I did to solve my issue. There is some issue with boundingRectWithSize and UILabels created using IBOutlets. So I did the above and then assigned that to a UILabel created using code and added that to the cell. And everything worked perfectly well!

- (void) layoutAnswerCell:(QXTAnswerCell*) answerCell
              AtIndexPath:(NSIndexPath*) indexPath
{
    if ([QXTUtility currentOsVersion] >= 7.0f)
    {
        [answerCell.answer removeFromSuperview];
        NSString *answerString = <your string>
        CGRect answerFrame = [answerString boundingRectWithSize:CGSizeMake(242.0f, 900.0f) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont fontWithName:@"Roboto-Light" size:14.0f]} context:nil];
        answerFrame.origin.x = 20.0f;

        answerFrame.origin.y = answerCell.name.frame.origin.y + answerCell.name.frame.size.height + 6;
        answerFrame.size.height = ceilf(answerFrame.size.height);
        answerFrame.size.height += 30.0f;
        answerCell.answer.lineBreakMode = NSLineBreakByTruncatingTail;
        answerCell.answer.frame = answerFrame;

        UILabel *newLabel = [[UILabel alloc] initWithFrame:answerFrame];
        [newLabel setFont:[UIFont fontWithName:@"Roboto-Light" size:14.0f]];
        newLabel.text = answerString;
        newLabel.numberOfLines = 0;
        [answerCell.contentView addSubview:newLabel];
        [answerCell setNeedsDisplay];
    }
}

See if this works for anyone else. If that's the case I'll accept this answer. But it did get the job done for me.

Upvotes: 1

mownier
mownier

Reputation: 1779

I think the problem lies in returning the correct height in tableView:heightForRowAtIndexPath:

It is returning always 64.0f at indexPath.row = 1

static CGFloat answerCellDefaultHeight = 200.0f; //change this to the actual value of the height of the answer table cell

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.row == 0) {
        return [self getHeightOfQuestion];
    } else if (indexPath.row == 1) {
        return 64.0f; 
    } else {
        CGFloat computedHeight = [self getHeightOfAnswerAtIndexPath:indexPath];
        return (computedHeight > answerCellDefaultHeight) ? computedHeight : answerCellDefaultHeight;
    }
}

Upvotes: 0

Related Questions