我正在構建一個消息屏幕作爲我正在寫的應用程序的一部分。目前,它是一個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:]
。它曾經抱怨過約束條件,但是這是一個糟糕的拍攝來重現這個錯誤。