André Fratelli
André Fratelli

Reputation: 6068

Adjust UITableViewCell's size to its contents

I'm trying to adjust a UITableViewCell's size to its content. This is basically for a chat view, where I list all previous messages and allow the user to scroll the conversation content.

So I have a UITableView with a few different cell prototypes. Incoming text messages, outgoing text messages, incoming image messages, outgoing image messages, and so on. Inside each cell's content view I have a standard UIView which I intent to use to draw the chat balloon. This view takes almost the cell's inner space (8px offset to the top, left, bottom, and right, all around). Inside that view I want the content. In the case of the text cells (incoming and outgoing) I want a UITextView which will display a text message. This is what I mean:

enter image description here

In yellow is the UIView and inside it the UITextView. Now I want to adjust everything to the text's size. I managed to accomplish the following:

  1. sizeToFit accomplishes exactly what I need for the UITextView
  2. I'm still not sure how to adjust the UIView's size to the UITextView's size.
  3. To adjust the cell's height maybe I could use heightForRowAtIndexPath. I don't need (nor do I think I should) to adjust the cell's width. But a few regards on that: when is this method called? Will the cell already have been instantiated? Will it have already layed out the subviews? Otherwise, how can I tell the content's size?

Any input on this is appreciated!

Edit:

I managed to make a few progresses by following the tutorial posted by @vikingosegundo, but I'm stuck again. This is what I have:

enter image description here

So, basically: the text view has constraints for leading, trailing, distance to top, and distance to bottom. The containing view, on the other hand, has constraints for trailing and distance to top, so that if the size is small then it snaps to the right. I can't had leading constraints or otherwise it will always take the full width of the cell. I'm not sure about distance to bottom constraints.

When a enter a small message it looks great. It's well sized and it snaps to the right.

enter image description here

However, long messages don't span to several lines. Instead it still snaps to the right (OK), but the width grows to the left, indefinitely.

enter image description here

The cell is already adjusting its height to the content's height:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    HyConversationTableViewCell * cell = (HyConversationTableViewCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath];
    CGSize size;

    [cell setNeedsLayout];
    [cell layoutIfNeeded];

    size = [cell.textMessageView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

    return size.height + 32;
}

I'm guessing that what I need now is something like a text view's maximum width or something, but I realise that's not possible. How do I solve this?

Edit: If I had a leading constraint to the containing view it looks great when the text spans multiple lines, but not when it doesn't. Here's what it looks like:

enter image description here

And:

enter image description here

Edit: As suggested by Alex Zavatone, I changed tableView:heightForRowAtIndexPath: to the following:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    HyConversationTableViewCell * cell = (HyConversationTableViewCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath];

    CGSize overflowSize = CGSizeMake(cell.textMessageView.frame.size.width, FLT_MAX);
    CGSize sizeAdjusted = [cell.textMessageView sizeThatFits:overflowSize];

    return sizeAdjusted.height + 32.0f;
}

It shows a little better as the height is already adjusted, but the behaviour is somewhat erratic. Here's what it looks like at the beginning:

enter image description here

So the height is correct, but the text view does not adjust its width. Also, if I scroll the cells out of screen and then back in (which forces them to redraw) they start behaving erratically in what seems a random criteria. Here's a sample:

enter image description here

Sometimes this happens to the last two cells...

Edit: That last part was fixed by setting Content Hugging Priority and Content Compression Resistance Priority to required and the Intrinsic Size to Placeholder. Now the height shows properly.

Upvotes: 0

Views: 492

Answers (3)

Bouabane Mohamed Salah
Bouabane Mohamed Salah

Reputation: 527

If you are using iOS 8 you can use UITableViewAutomaticDimension.

You can check out this example

self.tableView.rowHeight = UITableViewAutomaticDimension;

You can take a look also on this video : What's New in Table and Collection Views in the 2014 WWDC.

Upvotes: 4

l0gg3r
l0gg3r

Reputation: 8954

Here how, we are doing that

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

    AFMediaWithHeadlineCell *cell = [[[NSBundle mainBundle] loadNibNamed:@"AFMediaWithHeadlineCell"
                                                                                   owner:nil
                                                                                 options:nil] firstObject];
   [cell loadText:@"Some text"];
   return [cell height];
}

actually loadText: loads data into UI, and sizeToFits it. and height is basic method that calculates cell's height

- (void)loadText:(NSString *)aText
{
     self.textView.text = aText;
     [self.textView sizeToFit];
}

- (CGFloat)height
{
    return self.textView.frame.origin.y + self.textView.frame.size.height + 10; // 10 is margin 
}

Upvotes: 1

Alex Zavatone
Alex Zavatone

Reputation: 4323

You can resize the text by setting the height to a large number and then using sizeThatFits on it.

Not sizeToFit.

Like so:

    UILabel *label = self.prototypeCell.descriptiveText;
    label.numberOfLines = 0;
    CGSize sillyLargeHeight = CGSizeMake(label.frame.size.width, 9999);
    CGSize labelFrameAdjustedForHeight = [label sizeThatFits:sillyLargeHeight];
    return labelFrameAdjustedForHeight.height + 24.0; // 24 is 12 above and 12 below padding.

You can use a label or a textView. If you choose to use a UILabel, you'll need to set the # of lines to 0 so that it will be multiple line.

You can do this within - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

You'll also need to do the same adjustments to set the height on the field (use an IBOutlet) in the willDisplayCell method.

Upvotes: 0

Related Questions