UITableViewCell内部UITextView自动布局iOS 6与iOS 7
作为我正在编写的应用程序的一部分,我正在构建一个消息屏幕。目前,它是一个UITableViewCell内部UITextView自动布局iOS 6与iOS 7,ios,objective-c,uitableview,autolayout,Ios,Objective C,Uitableview,Autolayout,作为我正在编写的应用程序的一部分,我正在构建一个消息屏幕。目前,它是一个UITableView,包含我自己的UITableViewCell自定义子类的单元格。我正在使用界面生成器中定义的单元格上带有约束的自动布局。我的短信模仿或试图模仿默认的短信应用程序。每个表视图单元格有三个主要组件:一个UITextView包含消息正文和两个附加的UILabels,一个用于发件人的姓名和/或时间戳,另一个用于已送达/已读回执 现在,在我的视图控制器上,使用自动布局与tableView:heightForRow
UITableView
,包含我自己的UITableViewCell
自定义子类的单元格。我正在使用界面生成器中定义的单元格上带有约束的自动布局。我的短信模仿或试图模仿默认的短信应用程序。每个表视图单元格有三个主要组件:一个UITextView
包含消息正文和两个附加的UILabel
s,一个用于发件人的姓名和/或时间戳,另一个用于已送达/已读回执
现在,在我的视图控制器上,使用自动布局与tableView:heightForRowAtIndexPath:
相结合,消息在每个表视图单元格中的文本视图应该根据消息的大小而增长(我目前使用的是sizeWithFont:constainedToSize:lineBreakMode
——我知道它已经被弃用了,但替代品在iOS 6上不起作用,而且到目前为止还很脆弱)。当标签和文本视图都出现在UI上时,这可以正常工作。但是,在单个消息线程中,我使用removeFromSuperview
为所有消息单元格删除已传递/已阅读标签,但最终消息除外(如果所述最终消息由您发送)。这不会对iOS 7造成不利影响,但在iOS 6上,任何移除标签的单元格都会导致文本视图的高度为0.0
(通过调试输出确认)。以编程方式重新添加标签和适当的自动布局约束似乎可以解决此问题,但在删除该标签的任何单元格中,即使我在tableView:heightForRowAtIndexPath:
中计算文本视图的正高度,文本视图的高度为零,剩余的标签最终会向上移动到“出现”以覆盖编辑文本视图
我想从superview中删除一个视图是罪魁祸首,但我不明白为什么这只会发生在iOS 6上,而不是在iOS 6和iOS 7上
下面是我的cellforrowatinexpath:
和heightforrowatinexpath:
方法
- (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在-[UITableViewCell layoutSublayersOfLayer:]中抛出
断言失败
即使我的自定义子类没有实现该功能。它以前曾抱怨过约束,但复制该错误是一个废物。我通过让步解决了这个问题,并始终将两个UILabel
都放在单元格上。我只会巧妙地安排日期和读取时间。我会把它留在ca中有人将来也会遇到类似的问题