我正在构建一个消息屏幕作为我正在写的应用程序的一部分。目前,它是一个UITableView
,包含我自己定制的子类UITableViewCell
。我正在使用自动布局,对Interface Builder中定义的单元格有约束。我的消息模仿或试图模仿默认消息应用程序。每个表视图单元格有三个主要组件:一个UITextView
,其中包含邮件正文和两个额外的UILabel
,一个用于发件人姓名和/或时间戳,另一个用于发送/读取收据。UITextView里面的UITableViewCell自动布局iOS 6与iOS 7
现在,使用自动布局tableView:heightForRowAtIndexPath:
我的看法控制器相结合,在每个表视图细胞消息的文本视图应该根据消息有多大成长(我用sizeWithFont:constainedToSize:lineBreakMode
目前 - 我知道这是不推荐使用,但替代品在iOS 6上不起作用,并且至今还很脆弱)。如果标签和文本视图都显示在用户界面上,这可以正常工作。但是,在单个消息线程中,我使用removeFromSuperview
为所有消息单元除去最终消息(如果最终消息由您发送),则删除已发送/已读标签。这不会对iOS 7造成负面影响,但在iOS 6上,任何删除了标签的单元格都会导致文本视图的高度为0.0
(由调试输出确认)。以编程方式重新添加标签和相应的自动布局约束似乎可以修复它,但在删除标签的任何单元格中,即使我计算tableView:heightForRowAtIndexPath:
中文本视图的正高度,文本视图高度为零,其余标签结束向上移动到“出现”以覆盖文本视图。
我猜去除它的父视图是主要的罪魁祸首在这里,但我不明白为什么这会仅在iOS 6,而不是两个6和7
现在,代码中出现。这是我cellForRowAtIndexPath:
和heightForRowAtIndexPath:
方法
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * sentMessageCellIdentifier = @"sentMessageCell";
static NSString * receivedMessageCellIdentifier = @"receivedMessageCell";
MessageCell * cell;
Message * messageObject = [associatedThread.messages objectAtIndex:indexPath.row];
GroupMember * selfMm = [associatedThread.parentGroup groupMemberForUser:[ApplicationInstance getInstance].currentUser];
if ([messageObject.sender isEqualToGroupMember:selfMm]) {
// Sent
cell = (MessageCell *) [tableView dequeueReusableCellWithIdentifier:sentMessageCellIdentifier];
cell.sentTimeLabel.text = [UtilityFunctions messageFriendlyFormattedDateTimeForDate:messageObject.messageTime];
if ([messageObject isEqualToMessage:[associatedThread.messages lastObject]]) {
cell.deliveredReadByLabel.text = @"Sent";
} else {
cell.deliveredReadByLabel.text = nil;
}
} else {
// Received
cell = (MessageCell *) [tableView dequeueReusableCellWithIdentifier:receivedMessageCellIdentifier];
[cell setSenderAndDateTimeForSender:messageObject.sender date:messageObject.messageTime];
}
// Read by label
NSString * readByText = nil;
if (associatedThread.parentGroupMember == nil) {
// Group thread
if (messageObject.readBy.count == 0) {
if (![messageObject.sender isEqualToGroupMember:selfMm]) {
readByText = @"Read by: only you";
}
} else {
NSInteger readByCount = messageObject.readBy.count;
NSInteger toSubtract = [messageObject.sender isEqualToGroupMember:selfMm] ? 1 : 2;
if (readByCount == associatedThread.members.count - toSubtract) { // If everyone read it (minus you and the sender)
readByText = @"Read by everyone";
} else {
GroupMember * randRbm = [messageObject.readBy firstObject];
if (messageObject.readBy.count == 1) {
cell.deliveredReadByLabel.text = [NSString stringWithFormat:@"Read by: %@", randRbm.user.displayName];
} else if (messageObject.readBy.count > 1) {
cell.deliveredReadByLabel.text = [NSString stringWithFormat:@"Read by: %@ + %d", randRbm.user.displayName, messageObject.readBy.count - 1];
}
cell.deliveredReadByLabel.userInteractionEnabled = YES;
[cell.deliveredReadByLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapReadByLabel:)]];
}
}
} else {
// One-on-one individual thread
if ([messageObject isEqualToMessage:[associatedThread.messages lastObject]] &&
[messageObject.sender isEqualToGroupMember:selfMm]) {
if (cell.deliveredReadByLabel.superview == nil) {
[cell.contentView addSubview:cell.deliveredReadByLabel];
// Auto-layout bindings
NSArray * constaints = @[[NSLayoutConstraint constraintWithItem:cell.deliveredReadByLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:cell.sentTimeLabel
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:1.0],
[NSLayoutConstraint constraintWithItem:cell.deliveredReadByLabel
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:cell.contentView
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:20.0],
[NSLayoutConstraint constraintWithItem:cell.deliveredReadByLabel
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:cell.contentView
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:-20.0],
[NSLayoutConstraint constraintWithItem:cell.deliveredReadByLabel
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:cell.contentView
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-5.0]
];
[cell addConstraints:constaints];
}
if (messageObject.readBy.count == 1) {
readByText = @"Read";
}
} else {
[cell.deliveredReadByLabel removeFromSuperview];
}
}
if (readByText != nil) {
cell.deliveredReadByLabel.text = readByText;
}
debugLog(@"%@", [messageObject isEqualToMessage:[associatedThread.messages lastObject]] ? @"YES" : @"NO");
debugLog(@"x,y [%f, %f] | w,h [%f, %f] - message view", cell.messageView.frame.origin.x, cell.messageView.frame.origin.y, cell.messageView.frame.size.width, cell.messageView.frame.size.height);
debugLog(@"x,y [%f, %f] | w,h [%f, %f] - sent time label", cell.sentTimeLabel.frame.origin.x, cell.sentTimeLabel.frame.origin.y, cell.sentTimeLabel.frame.size.width, cell.sentTimeLabel.frame.size.height);
debugLog(@"x,y [%f, %f] | w,h [%f, %f] - sender time label", cell.senderAndDateTimeLabel.frame.origin.x, cell.senderAndDateTimeLabel.frame.origin.y, cell.senderAndDateTimeLabel.frame.size.width, cell.senderAndDateTimeLabel.frame.size.height);
debugLog(@"x,y [%f, %f] | w,h [%f, %f] - delivered label", cell.deliveredReadByLabel.frame.origin.x, cell.deliveredReadByLabel.frame.origin.y, cell.deliveredReadByLabel.frame.size.width, cell.deliveredReadByLabel.frame.size.height);
// Message body
[UtilityFunctions setZeroInsetsForTextView:cell.messageView];
cell.messageView.text = messageObject.messageBody;
cell.messageView.scrollEnabled = YES;
cell.messageView.scrollEnabled = NO;
return cell;
}
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *) indexPath {
CGFloat totalHeight = 0.0;
Message * m = [associatedThread.messages objectAtIndex:indexPath.row];
// Top and bottom padding
totalHeight += 5.0 + 5.0;
// Height + padding between labels (and text view)
totalHeight += 14.0 + 14.0 + 1.0 + 1.0; // height + height + padding + padding
// Modify UI slightly if incoming message and one-on-one thread:
if (associatedThread.parentGroupMember != nil) {
totalHeight -= (14.0 + 1.0);
if ([m isEqualToMessage:[associatedThread.messages lastObject]]) {
if ([m.sender isEqualToGroupMember:[associatedThread.parentGroup groupMemberForUser:[ApplicationInstance getInstance].currentUser]]) {
totalHeight += (14.0 + 1.0);
}
}
}
NSString * bodyText = m.messageBody;
CGSize constraint = CGSizeMake(MESSAGE_TEXT_WIDTH_MAX, CGFLOAT_MAX);
CGSize sizeWithFont = [bodyText sizeWithFont:[UIFont systemFontOfSize:16.0] constrainedToSize:constraint lineBreakMode:NSLineBreakByWordWrapping];
totalHeight += sizeWithFont.height + 1.0; // 1.0 because iOS hates me
if ([m isEqualToMessage:[associatedThread.messages lastObject]]) {
debugLog(@"YES");
} else {
debugLog(@"NO");
}
debugLog(@"height: %f", totalHeight);
return totalHeight;
}
下面是我在Interface Builder设置的约束。注意消息文本视图的静态宽度:
这里是它的外观在iOS 6中(注:颜色是我自己的助视器,它显然不会保持下去,并模拟器/装置产生相同的结果):
这里是在IOS 7的预期的行为,因为我希望人们表现:
重要的是要注意到实际表格视图单元本身的高度似乎是正确的,但是文本视图并未进行相应调整,尽管能够尝试在上述两种方法中调整我的代码并试图使用不同的技巧无济于事。我相当肯定,我需要使用removeFromSuperview
,因为这是使用自动布局和适应我所要做的唯一方法。交付/读取标签获取下列情况下删除:
- 里有消息线程
- 该消息是在线程的最新消息
- 这最后一条消息是由您 派两个人
我知道这是一个非常具体的问题,但如果任何人有想法,为什么会发生这种情况,我将不胜感激。请注意,文本视图不可编辑,尽管它是可选的。
一如既往,谢谢。
编辑:即使我的自定义子类没有实现该功能,我偶尔也会得到iOS 6的Assertion failure in -[UITableViewCell layoutSublayersOfLayer:]
。它曾经抱怨过约束条件,但是这是一个糟糕的拍摄来重现这个错误。