Luda
Luda

Reputation: 7068

What is the relationship between cellForRowAtIndexPath and heightForRowAtIndexPath

Where do I use the height calculated in heightForRowAtIndexPath?

Sorry if the text is not too clear, this is Hebrew :) See, the second cell has 2 lines? So I wanted the cell to be higher. So, I've calculated the height of the cell acording to the text and then went to setup the cell. The background, for instance should have been as the size of the cell itself, and it all mixed up...

enter image description here

Here is the code:

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    AnswerObject* answer = self.question.answers[indexPath.row];
    CGFloat height = [AnswerTableViewCell answerCellHeight:answer];
    return height;
}

-(AnswerTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    AnswerTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[AnswerTableViewCell alloc] init];
    }

    AnswerObject* answer = self.question.answers[indexPath.row];

    [cell setupAnswerTableViewCell:self.question answer:answer row:indexPath.row];

    return cell;
}

AnswerTableViewCell:

- (id)init
{
    self = [super init];
    if (self) {

//        self.frame = CGRectMake(0, 0, 280, 77);

        self.backgroundColor = [UIColor clearColor];
        self.contentView.backgroundColor = [UIColor clearColor];

        self.answerLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 10, self.frame.size.width-20, self.frame.size.height)];
        self.answerLabel.numberOfLines = 20;
        self.answerLabel.textColor = [UIColor whiteColor];
        self.answerLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:16];
        self.answerLabel.textAlignment = NSTextAlignmentRight;
        self.answerLabel.lineBreakMode = NSLineBreakByWordWrapping;

        self.answerToggle = [[UIButton alloc]initWithFrame:CGRectMake(self.frame.size.width-50, 23, 30, 30)];

        self.backgroundImage = [[UIImageView alloc]init];
        self.backgroundImage.frame = self.bounds;

        [self addSubview:self.answerLabel];
        [self addSubview:self.answerToggle];
        [self addSubview:self.backgroundImage];
    }
    return self;
}


-(void)setupAnswerTableViewCell:(QuestionObject*)question
                         answer:(AnswerObject*)answer
                            row:(NSInteger)row{
    self.question = question;
    self.answer = answer;
    self.row = row;

    CGSize labelSize = [answer.answerText sizeWithFont:self.answerLabel.font constrainedToSize:CGSizeMake(self.answerLabel.frame.size.width, 100000) lineBreakMode:self.answerLabel.lineBreakMode];

//    self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, labelSize.height + 20);

    self.answerLabel.frame = CGRectMake(self.answerLabel.frame.origin.x, self.answerLabel.frame.origin.y, self.answerLabel.frame.size.width, labelSize.height);

    self.answerLabel.text = answer.answerText;

    [self.answerToggle addTarget:self
                          action:@selector(flip:)
                forControlEvents:UIControlEventTouchDown];


    self.answerToggle.tag = [answer.answerID intValue];

    if (self.row == 0) {
        self.backgroundImage.image = [UIImage imageNamed:@"List_Top_Item_Not_Selected_612x113px.png"];
    }
    else if (self.row == ([self.question.answers count] - 1)){
        self.backgroundImage.image = [UIImage imageNamed:@"List_Bottom_Item_Not_Selected_612x113px.png"];
    }
    else{
        self.backgroundImage.image = [UIImage imageNamed:@"List_Item_Not_Selected_612x113px.png"];
    }

}

+(CGFloat)answerCellHeight:(AnswerObject*)answer{
    CGSize labelSize = [answer.answerText sizeWithFont:[UIFont fontWithName:@"HelveticaNeue-Light" size:16] constrainedToSize:CGSizeMake(280, 100000) lineBreakMode:NSLineBreakByWordWrapping];

    return labelSize.height + 20;
}

Upvotes: 0

Views: 120

Answers (4)

Shubhank
Shubhank

Reputation: 21805

heightForRowAtIndexPath the UITableView ask the datasource for the height of the cell it should prepare before you can fill its contents.

The tableView then allocates that much size/space between two cells. The cells that go though there are still needed to be given by the datasource and that is done in cellForRowIndexPath method.

Edit

Your frames are overlapping as you are returning custom heights for the cell. but not using them in the cell and initializing subviews to other values.

You can use layoutSubviews to get proper height and lay out your views properly.. or use a extra parameter height in the setupAnswerCell method and pass in the custom height and layout your items there.

Upvotes: 1

Wain
Wain

Reputation: 119031

You don't use the height, you just provide it. The table view uses it to determine the overall height of the content and how to display the cell at that index path. The cell should expect to be laid out at the stated height / resize appropriately to that height.


When you're setting up your cell in code and not using auto-layout you should be setting the frame of the cell. It doesn't really matter what you set it to, but you should set it and then the frames of all subviews relative to it. You then need to add auto-resizing rules to all of the subviews. In your case, both subviews should specify flexible width and height rules.

Add these things to ensure your cell contents are laid out properly.

Upvotes: 0

matt
matt

Reputation: 535801

Here is example code:

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    int ix = indexPath.row;
    if ([NSNull null] == self.heights[ix]) {
        NSString* s = self.trivia[ix];
        CGFloat h = [self cellHeightForLabelString:s];
        self.heights[ix] = @(h);
    }
    return [self.heights[ix] floatValue];
}

I don't know when and how many times I will be asked for the height of any given row, and calculating the height takes a little bit of time, so I keep an array of all the heights, which starts out as an array of NSNull objects. If I have already calculated the height for the requested row, I return it. If I haven't, I calculate it, store it, and then I return it.

The runtime then makes each row the height that I requested.

Upvotes: 1

Woodstock
Woodstock

Reputation: 22936

The heightForRowAtIndexPath is a delegate method you implement, all you need to do is return the value for the height you want each cell to be and the TableView will 'use' the value and set the cell height itself.

cellForRowAtIndexPath is recursively called to layout the contents of each cell (set labels, imageViews for each cell etc) just before they're presented on screen.

Consider this simple heightForRowAtIndexPath:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    return 50;
}

If this was your implementation, each cell in your tableview would automatically have it's height set to 50 points.

You don't have to do anything more... Simply return the height value you want for each cell.

This is only a simple example, you could put some conditional logic in heightForRowAtIndexPath that makes every second cell (for example) a different height.

Upvotes: 1

Related Questions