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];
}