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中有人将来也会遇到类似的问题