2

I'm implementing chat in my project. I started with smileyborg's approach - using Auto Layout for dynamic table cells (example is here, SO post is here). But now I have to use UITextView to display chat messages, because I have to detect URLs, insert smile images inside text and detect touches on user nicknames in text, and none of UILabel-type classes that I know support all this stuff.

The problem is that UITextView does not automatically resize properly if I use the same code. It does resize, but I get a lot of warnings like that:

"<NSLayoutConstraint:0x173cea60 V:[GGTextView:0xad34600(60)]>",
"<NSLayoutConstraint:0x172e8a10 V:[GGTextView:0xad34600]-(0)-|   (Names: '|':UITableViewCellContentView:0x172e43d0 )>",
"<NSAutoresizingMaskLayoutConstraint:0x173cee80 h=--& v=--& V:[UITableViewCellContentView:0x172e43d0(82)]>",
"<NSLayoutConstraint:0x172e8990 V:|-(0)-[GGTextView:0xad34600]   (Names: '|':UITableViewCellContentView:0x172e43d0 )>"

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x173cea60 V:[GGTextView:0xad34600(60)]>

How should I do that properly? Here is my code

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

// Setup offscreen cell to calculate height

id chatObject = [self.messages objectAtIndex:indexPath.row];
GGTableViewCell *cell = [self setupOffscreenMessageCellWithMessage:chatObject];

[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];

cell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds));

[cell setNeedsLayout];
[cell layoutIfNeeded];

// Get the actual height required for the cell's contentView
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

// Add an extra point to the height to account for the cell separator, which is added between the bottom
// of the cell's contentView and the bottom of the table view cell.
height += 1.0f;

return height;
}

TableViewCell code:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {

    [self layoutSubviews];
}
return self;
}

- (void)layoutSubviews {  

[super layoutSubviews];
[self.contentView setNeedsLayout];
[self.contentView layoutIfNeeded];
}

- (void)setupWithMessage:(ChatMessage*)message {
   // ... setting up attributed string here    

self.messageTextView.attributedText = messageText;

[self setNeedsUpdateConstraints];
[self updateConstraintsIfNeeded];
}

And finally code of my UITextView's subclass to create height constraint based on content height:

@implementation GGTextView

- (void)layoutSubviews
{
    [super layoutSubviews];

    [self setNeedsUpdateConstraints];
}

- (void)updateConstraints
{
    CGSize size = [self sizeThatFits:CGSizeMake(self.bounds.size.width, FLT_MAX)];

    if (!self.heightConstraint) {
        self.heightConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0f constant:size.height];
        [self addConstraint:self.heightConstraint];
    }

    self.heightConstraint.constant = size.height;
    [super updateConstraints];
}
Community
  • 1
  • 1
Spail
  • 693
  • 1
  • 7
  • 21

3 Answers3

0

Are you using interface builder or instantiating your view from code? If you are using IB, you can increase the priorities on the constraints that you want to hold fast, and lower the priorities on constraints that can be adjusted when the view(s) are resized. Also, try setting the ones that can be adjusted as >= or <= constraints, and that should silence the warnings when things get resized.

Mike1in3
  • 481
  • 5
  • 6
  • I'm using Interface Builder. Well, I don't have that much constraints. Table view cell contains only TextView. I only have constraints that pin TextView to cell's contentView, one constraint for compression resistance and height constraint that I add in code. So they all are required. – Spail May 11 '14 at 12:04
0

I've had the same exact problem using a custom UITextView that sets-up a height constraint with a flexible height UITableViewCell. I've found that UITextViews generally don't work well with systemLayoutFittingSizeeven with a custom height constraint to act as it's intrinsicContentSize. Most of the time, it's just returning the wrong height and messing with UITableViewCell's autoresizing constraint.

The only solution I've found is to NOT use the custom text view (with constraints) and manually calculate the height of the cell. Your UITextView should have constraints for its edges to its superview instead. For calculating the height of the UITextView, I added the textView contents and used

CGFloat textViewHeight = [textView sizeThatFits:CGSizeMake(textView.frame.size.width, CGFLOAT_MAX)].height

From that, you should be able to calculate the rest of the cell's height.

mj_jimenez
  • 443
  • 2
  • 5
0

You can try changing the compression resistance priority on the UITextView in relation to the other objects in the cell.

Maria
  • 4,471
  • 1
  • 25
  • 26