Ryan
Ryan

Reputation: 7959

How to properly resize parent view based on sub-views? (UITableViewCell containing UITextView, for example)

In my case, how would I resize a UITableViewCell to accomodate the height of a UITextView that it contains?

I'm currently trying to achieve this using the following code:

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

    // init the font that we use
    UIFont *font = [UIFont fontWithName:@"SourceSansPro-Regular" size:16];

    if (indexPath.section == 0) {

        // get the text size of the thread
        CGSize textSize = [_thread.text sizeWithFont:font constrainedToSize:CGSizeMake(280, CGFLOAT_MAX) lineBreakMode:UILineBreakModeWordWrap];

        return textSize.height + 20;

    }

    // default
    return 60;

}

I feel like if I could just get access to the UITableViewCell in this method, then I could use the contentSize property of the UITextView in it, and return that. But I don't think that's possible at this point in the execution flow.

I can't just tweak that buffer, because it doesn't scale with the text size being returned by the get size function. The shorter the text, the more visible a larger buffer size is.

This is adjusting the height of the UITableViewCell, but it's not showing all of the UITextView inside of it. I've specified the width of the UITextView in the sizeWithFont:constrainedToSize:lineBreakMode: method, which is 280. I've specified that I wish to have essentially no maximum height, so that it can word-wrap as much as it needs to, using the CGFLOAT_MAX constant. I append a buffer of 20 units to the resulting height of the method call, because there is a 20 unit buffer above the UITextView, in my Storyboard, and I'd like to also have a 20 unit buffer below it.

The end result of all of this still has text being clipped off, though. Here is a picture of what I am talking about:

clipped cell contents

Any ideas?

Upvotes: 1

Views: 1009

Answers (1)

Ryan
Ryan

Reputation: 7959

I'm going to go ahead and answer my question. The answer to this comes in two steps.

First, adjust the size of the UITextView during your logic inside of the tableView:cellForRowAtIndexPath: method. Make sure to do this after making any changes to the text in the UITextView. I re-size my UITextView using the following method, inside of a subclass of UITableViewCell where self.text is the text view:

- (void)resizeTextView {

    // get the current frame size
    CGRect frame = self.text.frame;

    // set it to the height of the text view
    frame.size.height = self.text.contentSize.height;

    // set the new size of the text view
    self.text.frame = frame;

}

Next, I specify the height of the UITableViewCell inside of the tableView:heightForRowAtIndexpath: method. This is where most of the mystery exists, because to get the height for this row you have to calculate the height of any text that is going to be displayed in the row, along with anything else you need to calculate the height of. In my scenario, is was a UITextView. Without access to the UITableViewCell instance in this method, you're forced to use something like sizeWithFont:constrainedToSize:lineBreakMode:. But, I noticed this was not returning consistent heights for me. Or at least, not heights that seemed to make enough room for my text from the UITextView. That was the problem, though. The text view has additional left and right padding as well as different line heights, or something, than the sizeWithFont method uses.

So, after fudging the results of the sizeWithFont method for awhile, I ended up with the following code:

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

    // init the font that we use
    UIFont *font = [UIFont fontWithName:@"SourceSansPro-Regular" size:16];

    if (indexPath.section == 0) {

        // get the text size of the thread
        CGSize textSize = [_thread.text sizeWithFont:font constrainedToSize:CGSizeMake(280 - 16, CGFLOAT_MAX) lineBreakMode:UILineBreakModeWordWrap];

        // text height + padding
        return textSize.height + 40;

    } else if (indexPath.section == 1) {

        // get the comment for this row
        Comment *comment = [_comments objectAtIndex:indexPath.row];

        // get the heights of the text areas
        CGSize textSize = [comment.text sizeWithFont:font constrainedToSize:CGSizeMake(280 - 16, CGFLOAT_MAX) lineBreakMode:UILineBreakModeWordWrap];

        return textSize.height + 40;

    }

    return 60;

}

In the size constraint parameter, I subtract 16 units because the UITextView has a padding of roughly 8 units on both the left and right sides. This will give us a closer result to what we expected for the height of the text.

I also add some padding to the final height, of 40 units, because the row itself needs some padding around the UITextView.

There you go! Hope that helps.

Upvotes: 1

Related Questions